Contenu connexe Plus de imShining @DevCamp (10) 如何创建更加灵活的App | 大众点评 屠毅敏1. Android
DevCamp
Produced by CSDN
Website: http://devcamp.csdn.net/
Weibo: http://weibo.com/cmdnclub/
Thursday, August 2, 12
3. Why
• 无法消灭旧版本,版本维护周期过长
• 基于版本的迭代速度缓慢
• 上线后无法调整
• Bug造成的影响无法即使消除
• 。。。
Thursday, August 2, 12
5. 案例
• 2010年,当时用户体验最好,用户数最多的地图类应
用是Google Maps
• 但是Google Maps面临最大的问题是速度慢,经常被墙
• 国内的地图应用成为主流只是时间问题
• 如何在外部环境发生变化后及时调整?
Thursday, August 2, 12
6. 需求
• 避免弹出Pick Activity对话框,根据用户手机有没有安
装该地图应用决定默认打开哪款地图。优先级如下:
Priority List:
1. Google Maps
2. Google Maps (Brut)
3. 百度地图
4. 图吧地图
5. Mini Map
...
• 查看地图是⼀一个非常关键的功能点 ,优先级需要随时
调整,并在已发布的客户端也同时生效
Thursday, August 2, 12
7. 问题
• 每款地图应用都定义了自己的Intent调用方式
• 对于未知的地图应用,如何创建对应的Intent?
• 是否需要针对地图应用的版本号来采取不同的优先级
策略?
Thursday, August 2, 12
8. 最初方案
• 把策略和创建Intent交给服务器端解决
• bla bla ...
Thursday, August 2, 12
10. 最终方案
• 放弃支持未知地图应用
• 放弃支持版本号判断
• 把Priority List加入远程配置中
• 客户端负责顺序判断,并创建地图应用对应的Intent
Thursday, August 2, 12
11. 配置
Remote
http://api.myserver.com/config?
client=myapp&version=1.0&...
cached on local disk
{
ver:”20120701”,
mapList: [
“Baidu”,
“Google”,
“Google(Brut)”,
“Mapbar”,
...
]
}
Thursday, August 2, 12
12. 配置
Remote User
http://api.myserver.com/config?
SharedPreference
client=myapp&version=1.0&...
cached on local disk stored on local disk
{
ver:”20120701”,
mapList: [
{
“Baidu”,
mapList: [
“Google”,
“Baidu”
“Google(Brut)”,
]
“Mapbar”,
}
...
]
}
Thursday, August 2, 12
13. 配置
Default Remote User
MyApp.apk http://api.myserver.com/config?
SharedPreference
|-res client=myapp&version=1.0&...
|-raw
cached on local disk stored on local disk
|-default
{ {
ver: “20120101”, ver:”20120701”,
mapList: [ mapList: [
{
“Google”, “Baidu”,
mapList: [
“Google(Brut)”, “Google”,
“Baidu”
“Baidu”, “Google(Brut)”,
]
“Mapbar”, “Mapbar”,
}
... ...
] ]
} }
Thursday, August 2, 12
14. 配置
• 简单实用,可以满足大部分的简单需求
• 新版本提示
• 特定功能的开启或关闭
• 产品运营相关
• 等等
Thursday, August 2, 12
15. HTML5
Hybrid Application
Thursday, August 2, 12
16. PhoneGap
详见 http://phonegap.com
Thursday, August 2, 12
17. Why Not?
• PhoneGap要做到和Native Activity的整合较困难
• 2010年的手机性能运行PhoneGap的界面流畅度不好
• 好的Web前端设计师太难招了
• 那个时候还没有PhoneGap
Thursday, August 2, 12
18. Activity Stack
首页 dianping://home
活动推广(HTML) http://dianping.com/a1.html
列表 dianping://list?ids=12,32,44
商户详情 dianping://info?id=12
Thursday, August 2, 12
19. URL Scheme
• dianping://shopinfo?id=123456
<activity
android:name="com.dianping.find.ui.activity.ShopInfoActivity"
android:configChanges="orientation|keyboardHidden"
android:label="商户信息"
android:screenOrientation="nosensor" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="shopinfo"
android:scheme="dianping" />
</intent-filter>
</activity>
Thursday, August 2, 12
20. URL Scheme
• HTML
<a href="dianping://shopinfo?id=123456">查看商户详情</a>
• Intent
Intent i = new Intent(Intent.ACTION_VIEW,
Uri.parse("dianping://shopinfo?id=123456"));
startActivity(i);
Thursday, August 2, 12
21. Simple is best
• 概念简单,就跟打开网站⼀一样,很容易跟别人解释清
楚。
• 实现简单,几行代码就能实现。
• 跨平台,iOS和Android都可以采用。
• 微信、支付宝等程序间的交互。
Thursday, August 2, 12
22. 团购
• 需求变数多
• 主要业务由网站开发团队负责,移动只提供框架
• 用HTML开发,需要同时支持iOS和Android
• HTML能够向Java代码获取信息,如用户账户等信息
• 能够指定在不同的Activity中打开不同的页面
Thursday, August 2, 12
23. 数据传递
• Android Javascript Bridge
public void addJavascriptInterface(Object object, String name)
• WebView URL Override (Android & iOS)
public boolean shouldOverrideUrlLoading(WebView view, String url)
http://myapp.com/checkout?user=!&token=!
http://myapp.com/checkout?user=123&token=e3a12f54c123
Thursday, August 2, 12
25. 出现问题
• 不同Android版本的WebView有不⼀一致的行为
• 列表页面高度逐渐增大,UI相应速度缓慢直至完全不
响应
• jQuery或MooTools当时没有为移动设备做优化,类库
太重,耗费资源严重。
• 在不同的Activity和WebView中打开网页导致严重依赖
Cookie,管理成本高。
Thursday, August 2, 12
26. 最终
• 用户普遍不认可HTML的开发方式,各种抱怨
• 浏览率低,订单转化率低,支付成功率低,各种低
• 损失的都是钱那
Thursday, August 2, 12
27. 惨痛的教训
• 用户体验通常是Native比HTML好
• Web开发和移动开发还是有显著区别的,沟通成本很
高
• 如果HTML只是临时方案,不要做过多的框架设计,
但是⼀一定要考虑今后迁移到Native的可行性
• 考虑成本和收益
Thursday, August 2, 12
28. 脚本语言
Lua & Python
Thursday, August 2, 12
29. 脚本语言的问题
• dalvik下无法创建新的类
• Java是静态类型,脚本语言调用需要指定类型,代码非常冗余
• 使用C/C++实现的Lua和Python解释器面临的问题
• 无法直接在Lua/Python中引用Java对象(内存地址变化)
• 需要经过JNI来中转所有调用,中间层实现成本较高
Java JNI Lua/Python
• 使用Java实现的Lua和Python解释器效率较低,且可靠性未知
Thursday, August 2, 12
30. 动态加载
Dalvik Executable File
&
Resources
Thursday, August 2, 12
31. DexClassLoader
DexClassLoader dcl = new DexClassLoader(
"/sdcard/dex.apk", "/sdcard/dexout/",
null, super.getClassLoader());
Class c = dcl.loadClass("com.package.MyClass");
Object myObj = c.newInstance();
Thursday, August 2, 12
32. 定位项目需求
• 初步证明android.location.LocationManager存在优化空
间
• 进⼀一步的优化需要通过线上数据及反馈进行迭代
• 迭代周期为1~2周⼀一次
• 每次迭代都需要在线上环境做A/B Test以验证有效
Thursday, August 2, 12
33. 定位服务
dianping.apk dynamic.apk
interface LocationService
class LocationServiceImpl
class DexLocationServiceWrapper implements LocationService
implements LocationService
{
private LocationService mService;
}
Thursday, August 2, 12
34. 上线后
• 完全摆脱了App上线周期和版本的限制
• 新老版本的App都运行着最新版本的定位服务
• 不同App运行着最新版本的定位服务,不需要再merge
了
• 团队可以独立运作
• 偶尔还可以帮忙解个线上Bug。。
Thursday, August 2, 12
35. 下⼀一步
• 所有代码都动态加载
• 如何动态加载⼀一个Activity?
Thursday, August 2, 12
36. 动态加载Activity
Application
mBase : ContextImpl
mPackageInfo : LoadedApk
mClassLoader : PathClassLoader
Thursday, August 2, 12
37. DEMO
Activity Override
Thursday, August 2, 12
38. 缺陷
• 用了很多Hacking,不能保证未来系统的兼容性
• Activity必须要在AndroidManifest.xml中注册,所以无法
通过动态加载的方法新增Activity
• Resources资源文件没有解决
Thursday, August 2, 12
39. 重新思考
• Activity继承自ContextWrapper,每个Activity都有能力
改变自己的上下文环境。
• Android 3.0 引入了救星Fragment。Fragment就是小⼀一
号的Activity,但也能够满足需求了。
• Activity作为Fragment运行的容器,提供ClassLoader和
Resources相关的环境。
Thursday, August 2, 12
40. 代码 资源
Activity.getAssets()
Activity.getClassLoader() Activity.getResources()
Activity.getTheme()
Thursday, August 2, 12
41. DEMO
Fragment Loader
Thursday, August 2, 12
42. Resources重复问题
• Android的资源文件通过R.java来索引
• 手动分配不同的id,在不同层级的apk中通过res/values/
public.xml来分配
• 通过重载AssetManager中的隐藏函数来区分不同区段
的id,并返回对应apk包中的资源
• (需要特殊的编译方式)
Thursday, August 2, 12
43. 数据类型
• 采用Java类封装数据的方式过于繁重
• 建议采用松散数据类型在各个模块之间进行交互(类似
JSONObject)
Thursday, August 2, 12
44. 其他问题
• 模块粒度问题
• Intent如何表示
• 损失的Activity属性如何弥补
Thursday, August 2, 12
45. 优点
• 采用插件的模式,功能模块独立开发,独立上线
• 开发彻底解耦
• 解决了编译时间过长的问题
• 主程序apk包大小可以减小
Thursday, August 2, 12
46. HTML + Dex
Javascript Bridge
Thursday, August 2, 12