|
本帖最后由 dwchen1999 于 2013-9-18 10:13 编辑
终于在Google play发布了第一App。产品本身不算完善,市场前景心里也没底。但是在开发过程中碰到了不少的问题,把它记下来,一来以备将来查阅,二来可能帮助其他开发者。
设计的问题
开始开发前,我对产品的预期是要酷,界面要比较炫。但是很多没想到的问题相继出现,进度远落后于预期。这时必须权衡,要么追加预算,要么修改需求。对于我这个试探性的产品,没有进行仔细的市场调研。尽快上市,以获取真实的市场反馈,是第一位的。我就重新思考,我的产品的核心价值是什么,亮点是什么。如果能够突出这个亮点,其他一切都是都不重要了。经过这么一问,产品的界面从原来的5个页面精简到2个,大大的减少了工作量,也突出了产品的亮点。
我想值得肯定的经验是,突出产品的核心功能,尤其是在早期版本。
版本兼容
第一需要思考的是要兼容哪些版本安卓手机。我原来收集的资料是,如果要覆盖95%的手机的话,应该兼容API level 8(包含8)以上。后来,由于决定要用OBB附件来保护我的视频资料,同时避免自己设计一套保护机制,那么就要用到StorageManager类,而这个类要API Level9才有。只好把兼容的API LEVEL 提高到9。当我发布的时候,发现我的应用兼容了Google Play上所有的手机。 可以说,如果目标市场是Google Play,那么选择API LEVEL 9是保险的。
版本兼容的第一个问题就是ActionBar。第一要引入Support library V4,才能使用ActionBar; 其次,Activity要继承ActionBarActivity;要调getSupportActionBar()而不是getActionBar()来获得ActionBar。
版本兼容的第二个问题就是GridLayout要引入Support Library V7.
版本兼容的第三个问题就是StorageManager要API Level 9才有,support library V7,V8都没有.
版本兼容的第四个问题就是视频播放器。在原型阶段用把视频放在APK raw目录下, Android 4.1 和 2.3的手机都能播放。在产品阶段,把视频移到OBB内,实质是移到外部存储器。Android 4.1 的手机视频播放正常,2.3的就不能播放了。经过一番研究,视频播放是在另一个进程进行的,OBB文件只能被我的进程访问,播放器进程没有访问权限(新版本Android解决了这个问题)。解决办法有二,一是修改文件访问权限,二是修改视频播放代码。没有找到简洁的代码来修改权限。我选择的是修改视频播放代码。MediaPlayer setDataSource(FileDescriptor fd)函数就能兼容2.3版本的手机了。
延伸的问题就是,VideoView并没有暴露这个函数。继承VideoView也没法达成目标。我只能用暴力一点的办法,拷贝全部代码,修改要修改的部分。
屏幕兼容
要想让程序在不同尺寸的屏幕上都能显示正常,看起来舒服,基本的策略是为不同的尺寸的屏幕设计不同布局和外观。比如说,对于小屏幕,左边的导航栏分配200DP,右边的GridView 占满其余部分;对于大屏幕,左边的分配400DP。在实际中发现效果不理想。后来找到一个比较理想的办法,用百分比布局,左边40%,右边60%,在各种尺寸的屏幕上总体布局感觉不错。需要微调的就是不同屏幕的字体大小要改变。
百分比布局还是有点小技巧的。比如主画面,左边是个ScrollLayout,右边是个LinearLayout。自然的想法就是,左边的layout_weight =2, 右边的layout_weight=3. 可实际效果就是,左边完全不见,右边占全屏。诀窍就是把左边的ScrollLayout也套在一个LinearLayout内。
OBB 文件
OBB(Opaque Binary Blob)文件可以把应用程序的资源打包成一个大的文件,它里面的内容只有你直接App能访问,别的App不能访问。在使用时碰到不少问题。
1.生成时的陷阱
Jobb 是andoroid下的一个工具,可以将一个目录下的资源打包和加密,生成一个大的Obb文件。在使用过程中碰到多个问题。我选择了一个小目录,里面有上十个文件,总共3M多,执行以下命令:
jobb -pn com.cdw.easycharacter -pv 10 -o easycharacter .obb -k mypassword -d D:\test\55\assets
总是报错 Slop: 0 Directory Overhead: 0
Exception in thread "main" java.lang.IllegalArgumentException: disk too large for FAT12
经过一番研究,居然是要压缩目录D:\test\55\assets的文件总大小不够,我加了一个7M的文件进去,居然就可以了。后来我又把里面的一个子目录的文件复制一份,使文件夹总大小达到4M以上,也可以.。多么有趣的bug.明明是嫌文件少,却说"disk too large for FAT12".
第二问题是,运行不报错,但是找不到生成的文件.我在D:\test\55目录下找不到文件. 后来试了一下一下命令,
jobb -pn com.cdw.easycharacter -pv 10 -o D:\test\55\easy-app-assets.obb -k cdw -d D:\test\55\assets
在D:\test\55目录生成了目标文件.
2.读取时的陷阱
OBB文件的读取有mount 和 读取两步
陷阱一:不管密码是否正确,mount都返回true。有的特殊字符不可以用在密码里,我的密码有“@ &”jobb就不能压缩
陷阱二:mount成功不等于马上可以访问,StorageManager.mountObb将立即返回,但是obb访问要等到OnObbStateChangeListener 的回调
陷阱三:文件路径的问题,我用jobb命令把“d D:\test\55\assets”目录变成obb文件,原来assets目录下有:a.xml文件
陷阱四: 生成Obb文件的源文件的只读属性可能造成Obb mount失败,并且没有任何有价值的提示.
那访问的a.xml的路径是: StorageManager.getMountedObbPath(rawpath) + "/a.xml", 而不是StorageManager.getMountedObbPath(rawpath) + "/assets/a.xml"
经过测试,OBB文件的读取并不需要声明任何权限.
obb文件内不能有Obb文件,要不然mountObb将失败,并且没有提示。
Apk扩展文件下载
扩展文件的下载,直接集成Google的示例代码就可以了。问题就是下载URL的生成是Google Play生成的。测试必须和Google Play结合 起来。
应用内付费的问题
1.不方便测试
中国程序员不能发布付费(包括应用内付费)软件,这个问题倒不难,在注册开发者的时候,说是香港开发者就行了(香港就是中国嘛)。问题是Google Play Client(手机上的Google Play程序)不能显示付费软件,同时也不能初始化付费API。总之,付费的API没法测试。应对的策略就是冒充美国人。第一个尝试就是用Market Enabler,Market unloccker等APP,结果失败。第二个尝试就是翻墙,用美国IP访问Google Play,仍然失败。第三个尝试,先用远程终端操作美国的虚拟主机访问Google Play, 然后翻墙,启动Google Play Client,结果成功了。Google Play判断你是哪国人,我估计有以下几个因素,一个是关联的信用卡发卡国,这个具有最高优先级;其次根据位置信息决定你在哪里;运营商ID,IP,时间是其他因素。最后成功的策略,我估计是这样的:先用美国的虚拟主机使Google确认你在美国,翻墙冒用了美国IP。但是如果用移动网络,方案3也失败,说明运营商ID也是一个重要测试(Market Enabler主要是修改运营ID来起作用,看来被Google破了)。
2.public key 错误导致的问题
每个App有个Public Key,在提交APK之前生成的key 和提交及之后的Key有变化。这个我问题害我不浅。总是报Signiture verify失败。我想Key是拷贝过来的,一直没改过,一定正确,一定是其他参数有问题,可其他参数又不是我产生的。让我很崩溃。后来才明白Key变了。但是由于一点笔误,我新的Key也弄错了,超过原来的长度。一直程序崩溃,只说字符超长,我想我是拷贝过来的,一定不会错。
代码混淆的副作用
混淆后程序运行不正常了。真正的麻烦是,调试就非常困难了。经过一天多的苦苦寻觅,问题的原因重要找到了。就是下面这行代码工作出错了。
if (tag.getTagName().equals(Category.class.getSimpleName())) {
原因是是:Category.class.getSimpleName() 在混淆后返回的就是a 或b之类的单字母字串,我预期的是返回“Category”。
结论:如果要对代码进行混淆,就要考虑到类名,方法名和变量名在混淆时将改变。
修改的代码没有立即生效
有一次我为了测试应用内付费,故意修改代码,把一个ID 加100.
int id = 100 + category.getId();
在调试的时候,我查看category.getID()的值是1,执行完加100后,还是1。后来,我把加100去掉。结果是int id = category.getId(); id居然是101,尽管category.getId()的值还是1。我clean Project,重启电脑,结果还是如此,百思不得其解。
MediaPlayer播放多个视频后,有的视频不能播放了,重启程序就可以
这个问题,我一直没搞明白,为什么播了十几个视频后会有问题。每播一个新视频,我都把原来的释放了。会不会回收太慢了? |
|