Android工程师角度分析App使用的开源框架-3.菜鸟裹裹

自从分析完手淘后,感觉已经过去了一个世纪了,尴尬。本来上次说要分析京东和美团的,也没有开始着手,最近对智能物流比较感兴趣,所以这次分析的是菜鸟裹裹App。京东和美团的只能等后面了,抱歉。

App信息

文件: cainiao4android_10004264.apk
大小: 27.5M
版本: 4.7.1

反编译源码

这次反编译工具依然是jadx(如果有更好的工具,可以在留言推荐下哦)。
这次分析从AndroidManifest.xml文件开始, 菜鸟App的包名:com.cainiao.wireless

com.cainiao.wireless

源码分析:

AndroidManifest.xml中定义的Application:

1
2
3
4
5
<application android:theme="@style/Theme.AppCompat.Light.NoActionBar" android:label="菜鸟裹裹" android:icon="@drawable/ic_launcher" 
android:name="android.taobao.atlas.startup.AtlasBridgeApplication"
android:screenOrientation="portrait" android:allowBackup="false"
android:largeHeap="true" android:supportsRtl="false">
</application>

AtlasBridgeApplication是atlas框架下apk的真正Application,容器框架结构图:

具体原理参考:Atlas

真正的入口:

那真正的入口在哪里?
AtlasBridgeApplication的attachBaseContext方法中有一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
try {
Class loadClass = getBaseContext().getClassLoader().loadClass("android.taobao.atlas.versionInfo.BaselineInfoManager");
Object invoke = loadClass.getDeclaredMethod("instance", new Class[0]).invoke(loadClass, new Object[0]);
Field declaredField = loadClass.getDeclaredField("mVersionManager");
declaredField.setAccessible(true);
declaredField.set(invoke, KernalVersionManager.instance());
loadClass = getBaseContext().getClassLoader().
loadClass("android.taobao.atlas.bridge.BridgeApplicationDelegate");
this.mBridgeApplicationDelegate = loadClass.getConstructor(new Class[]{Application.class, String.class, String.class, Long.TYPE, Long.TYPE, String.class, Boolean.TYPE, Object.class}).newInstance(new Object[]{this, KernalConstants.PROCESS, KernalConstants.INSTALLED_VERSIONNAME, Long.valueOf(KernalConstants.INSTALLED_VERSIONCODE), Long.valueOf(KernalConstants.LASTUPDATETIME), KernalConstants.APK_PATH, Boolean.valueOf(isUpdated), KernalConstants.dexBooster});
loadClass.getDeclaredMethod("attachBaseContext", new Class[0]).invoke(this.mBridgeApplicationDelegate, new Object[0]);
} catch (Throwable th) {
RuntimeException runtimeException = new RuntimeException(th);
}

可以看出实际加载的是BridgeApplicationDelegate这个类的attachBaseContext方法,该方法也有一段主要逻辑:

1
2
3
4
5
ApplicationInfo applicationInfo = this.mRawApplication.getPackageManager().getApplicationInfo(this.mRawApplication.getPackageName(), 128);
this.mRealApplicationName = applicationInfo.metaData.getString("REAL_APPLICATION");
if (applicationInfo.metaData.getBoolean("multidex_enable")) {
MultiDex.install(this.mRawApplication);
}

所以最后其实加载的真正入口就是在AndroidManifest.xml中的名称为REAL_APPLICATION的meta-data标签:

1
2
3
<meta-data android:name="REAL_APPLICATION" 
android:value="com.cainiao.wireless.CainiaoApplication" />
<meta-data android:name="multidex_enable" android:value="true" />

简单分析下 CainiaoApplication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class CainiaoApplication extends CommonLibraryApplication 
implements ReactApplication {
...
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
protected boolean getUseDeveloperSupport() {
return false;
}

protected List<ReactPackage> getPackages() {
return Arrays.asList(new ReactPackage[]{new MainReactPackage(),
new CNReactPackage()});
}
};

public void onCreate() {
super.onCreate();
if (AppUtils.isDebugMode) {
if (!LeakCanary.isInAnalyzerProcess(this)) {
if ("true".equals(SharedPreUtils.getInstance().getLeakCanaryFlag())) {
LeakCanary.install(this);
}
initStetho();
} else {
return;
}
}
Atlas.getInstance().setBundleSecurityChecker(new BundleVerifier() {
public boolean verifyBundle(String bundlePath) {
try {
if (SecurityGuardManager.getInstance(CommonLibraryApplication.application.getApplicationContext()) != null) {
IPkgValidityCheckComponent packageValidityCheckComp = com.taobao.wireless.security.sdk.SecurityGuardManager.getInstance(CommonLibraryApplication.application.getApplicationContext()).getPackageValidityCheckComp();
if (packageValidityCheckComp != null) {
return packageValidityCheckComp.isPackageValid(bundlePath);
}
}
return true;
} catch (Throwable e) {
throw new RuntimeException("SecException ErrorCode=" + e.getErrorCode(), e);
}
}
});
...

registerActivityLifecycleCallbacks();
}
}

实现了ReactApplication,加载CNReactPackage模块。
在调试状态下,可以开启LeakCanary,Stetho
注册了ActivityLifecycleCallbacks回调,具体作用等后期模块分析,在具体介绍。
本次的目的主要分析使用的开源框架。

wireless包结构:

包名 描述 框架
adapter 各种adapter
cdss 数据模型的定义。(db,orm,protocol请求和响应,数据日志记录和同步等)
components 组件库。(dao,windvane、weex、rn的hybrid实现,api服务等) windvane,weex,rn
data po,jo定义
im 使用RN模块实现
jsbridge 定义同步和异步的jsEvent
location 定位功能,定义了一些模型 高德地图实现
locus 定位功能,主要功能实现
mtop 淘宝开放平台api(request和response)
mvp mvp模型实现
pegasus 飞马日志统计(阿里都喜欢以动物命名)
phenix cache模块
postman.data.api 测试mtop数据接口吗?
uikit 自定义view定义
utils 工具类定义
wangxin.rn 旺信rn模块
widget 自定义widget
wxapi 微信接入

其他包结构


名称 包名 描述
atlas android.taobao.atlas 动态组件化框架
windvane android.taobao.windvane 手淘h5框架
com.android.dingtalk.share.ddsharemodule com.android.dingtalk.share.ddsharemodule 钉钉分享模块
fresco com.facebook.fresco facebook fresco图片加载
React Native com.facebook.react react native,闲鱼已经开始使用Flutter了,阿里还真的是走在技术前沿啊
zxing com.google.zxing 二维码
leakcanary com.squareup.leakcanary 内存泄露检测工具
EventBus2.x de.greenrobot.event 事件总线框架
greenDAO2.x de.greenrobot.dao 数据库框架
mtopsdk 阿里云开放平台
zbar net.sourceforge.zbar 二维码 c语言实现
okhttp okhttp3 http网络库,Android必备库

一些比较细节的或者改造过的库,没有去穷举。
通过上面库的使用分析,菜鸟app在hrbird上运用比较多,这个与实际的业务有关(具体哪些业务上使用了,接下来会有一些列文章来分析)。
其他一些库,和以前阿里系的还是比较类似,使用了很多的主流库。
接下来会对菜鸟app进行更深一步的分析,具体分析哪些内容,正在整理中。

yeungeek wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
曾经有一份打赏放在我面前,我没有珍惜.如果上天给我再来一次的机会,我会说:来着不拒.