AirJD 焦点
AirJD

没有录音文件
00:00/00:00
加收藏

Small:插件化轻巧之道-移动App开发 by 林光亮

发布者 mobile
发布于 1468889781379  浏览 6339 关键词 移动开发 
分享到

第1页

Small:插件化轻巧之道

林光亮



第2页

0x00



诞生



0x01







0x02







0x03



TODO



第3页

诞生



模块1



模块2



模块3



模块4



模块5



模块6



第4页

诞生



分析支付宝客户端插件机制 @唐巧-­‐猿题库



手机淘宝客户端架构探索实践 @于佳-­‐阿里



第5页

诞生



+ iOS



HTML



Android



Bundle
 L auncher



第6页

诞生



Android



Dynamic-­‐Load-­‐APK @任玉刚-­‐百度



Direct-­‐Load-­‐APK @罗迪-­‐高中生



第7页

诞生 Host



模块1 模块2

模块3



第8页

诞生 Host



模块1

公共 模块

模块3



第9页

诞生

使用public.xml 锁定公共资源ID

公共 模块

Host

DLA 改进

打通宿主与插件的 资源与代码共享



模块1 模块3



第10页

诞生

使用public.xml 锁定公共资源ID

公共 模块

Host

DLA 改进

打通宿主与插件的 资源与代码共享



模块1 模块3



第11页

诞生



Android-­‐Plugin-­‐Framework @Limpoxe



ACDD @Bunny Blue



第12页

诞生 aapt



模块1 0x7A

模块2 0x7B 模块3 0x7C



第13页

诞生 aapt



模块1 0x7A

模块2 0x7B 模块3 0x7C



第14页



BA C

A

轻盈产出 @Compile-­‐time



A A’

B

轻度Hook @Run-­‐time



第15页

轻/轻盈产出 APK



第16页

轻/轻盈产出



AM.xml classes.dex resources.arsc

res/*



第17页

轻/轻盈产出



拆分粒度/方案

文本



AM$1



文件(*.jar)



dex$1



二进制



arsc$1



文件(*.xml/png)



res$1



AM.xml classes.dex resources.arsc

res/*



AM$2 dex$2 arsc$2 res$2



第18页

轻/轻盈产出/arsc格式



0000000: 0200 0c00 4804 0000 0100 0000 0100 1c00 0000010: 8c00 0000 0400 0000 0000 0000 0001 0000 0000020: 2c00 0000 0000 0000 0000 0000 2500 0000

0000030: 4800 0000 5700 0000 2222 7265 732f 6d69 0000040: 706d 6170 2d68 6470 692d 7634 2f69 635f 0000050: 6c61 756e 6368 6572 2e70 6e67 0020 2072 0000060: 6573 2f6d 6970 6d61 702d 6864 7069 2d76 0000070: 342f 6963 5f70 6c75 6769 6e2e 706e 6700

0000080: 0c0c 4c65 6172 6e69 6e67 4172 7363 0006 0000090: 0650 6c75 6769 6e00 0002 2001 b003 0000 00000a0: 7f00 0000 6e00 6500 7400 2e00 7700 6500 00000b0: 7100 7500 6900 6300 6b00 2e00 6100 7200 00000c0: 7300 6300 0000 0000 0000 0000 0000 0000

00000d0: 0000 0000 0000 0000 0000 0000 0000 0000 00000e0: 0000 0000 0000 0000 0000 0000 0000 0000 00000f0: 0000 0000 0000 0000 0000 0000 0000 0000 0000100: 0000 0000 0000 0000 0000 0000 0000 0000 0000110: 0000 0000 0000 0000 0000 0000 0000 0000

0000120: 0000 0000 0000 0000 0000 0000 0000 0000 0000130: 0000 0000 0000 0000 0000 0000 0000 0000



....H........... ................ ,...........%...

H...W...""res/mi pmap-hdpi-v4/ic_ launcher.png. r es/mipmap-hdpi-v 4/ic_plugin.png.

..LearningArsc.. .Plugin... ..... ....n.e.t...w.e. q.u.i.c.k...a.r. s.c.............

................ ................ ................ ................ ................

................ ................



第19页

轻/轻盈产出/arsc格式



0000000: 0200 0c00 4804 0000 0100 0000 0100 1c00 0000010: 8c00 0000 0400 0000 0000 0000 0001 0000 0000020: 2c00 0000 0000 0000 0000 0000 2500 0000

0000030: 4800 0000 5700 0000 2222 7265 732f 6d69 0000040: 706d 6170 2d68 6470 692d 7634 2f69 635f 0000050: 6c61 756e 6368 6572 2e70 6e67 0020 2072 0000060: 6573 2f6d 6970 6d61 702d 6864 7069 2d76 0000070: 342f 6963 5f70 6c75 6769 6e2e 706e 6700

0000080: 0c0c 4c65 6172 6e69 6e67 4172 7363 0006 0000090: 0650 6c75 6769 6e00 0002 2001 b003 0000 00000a0: 7f00 0000 6e00 6500 7400 2e00 7700 6500 00000b0: 7100 7500 6900 6300 6b00 2e00 6100 7200 00000c0: 7300 6300 0000 0000 0000 0000 0000 0000

00000d0: 0000 0000 0000 0000 0000 0000 0000 0000 00000e0: 0000 0000 0000 0000 0000 0000 0000 0000 00000f0: 0000 0000 0000 0000 0000 0000 0000 0000 0000100: 0000 0000 0000 0000 0000 0000 0000 0000 0000110: 0000 0000 0000 0000 0000 0000 0000 0000

0000120: 0000 0000 0000 0000 0000 0000 0000 0000 0000130: 0000 0000 0000 0000 0000 0000 0000 0000



....H........... ................ ,...........%...

H...W...""res/mi pmap-hdpi-v4/ic_ launcher.png. r es/mipmap-hdpi-v 4/ic_plugin.png.

..LearningArsc.. .Plugin... ..... ....n.e.t...w.e. q.u.i.c.k...a.r. s.c.............

................ ................ ................ ................ ................

................ ................



第20页

轻/轻盈产出/arsc格式



hex(LE) 小端代码



struct 数据结构



0200 ResTable_header



0100 ResStringPool_header



0002 ResTable_package



0100 ResStringPool_header



0100 ResStringPool_header



0202 ResTable_typeSpec



0102 ResTable_type



0200 0c00 4804 0000 0100 0000 0100 1c00 8c00 0000 0400 0000 0000 0000 0001 0000 2c00 0000 0000 0000 0000 0000 2500 0000

4800 0000 5700 0000 2222 7265 732f 6d69 706d 6170 2d68 6470 692d 7634 2f69 635f 6c61 756e 6368 6572 2e70 6e67 0020 2072 6573 2f6d 6970 6d61 702d 6864 7069 2d76 342f 6963 5f70 6c75 6769 6e2e 706e 6700

0c0c 4c65 6172 6e69 6e67 4172 7363 0006 0650 6c75 6769 6e00 0002 2001 b003 0000 7f00 0000 6e00 6500 7400 2e00 7700 6500 7100 7500 6900 6300 6b00 2e00 6100 7200

7300 6300 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000



第21页

轻/轻盈产出/arsc格式



hex(LE) 小端代码



struct 数据结构



0200 ResTable_header



0100 ResStringPool_header



0002 ResTable_package



0100 ResStringPool_header



0100 ResStringPool_header



0202 ResTable_typeSpec



0102 ResTable_type



table: { package: { id: 0x7F, name: "net.wequick.arsc" }, strings: [ "res/mipmap-hdpi-v4/ic_launcher.png", "res/mipmap-hdpi-v4/ic_plugin.png", "LearningArsc", "Plugin" ], typeStrings: [ "attr", "mipmap", "string", "style" ], keyStrings: [ "ic_launcher", "ic_plugin", "app_name", "s_plugin", "AppTheme", "PluginTheme" ], typeSpecs: [ { types: [] }, { types: [ Configs@ic_launcher, Configs@ic_plugin ] }, { types: [ Configs@app_name, Configs@s_plugin ] }, { types: [ Configs@AppTheme, Configs@PluginTheme ] } ]

}



第22页

轻/轻盈产出/arsc格式



资源ID 0x



PP 包ID

7F



TT NNNN 类型ID 项目ID

02 0000



table: {



package: { id: 0x7F, name: "net.wequick.arsc" },



strings: [



"res/mipmap-hdpi-v4/ic_launcher.png",



"res/mipmap-hdpi-v4/ic_plugin.png",



"LearningArsc",



"Plugin" ],







03 04



typeStrings: [ "attr", "mipmap", "string", "style" ],



keyStrings: [



"ic_launcher", "ic_plugin", "app_name",



"s_plugin", "AppTheme", "PluginTheme"



],



typeSpecs: [



01 { types: [] },





{ types: [ CCoonnffigigss@@icic__lalauunncchheer,r Configs@ic_plugin ] },

03 { types: [ Configs@app_name, Configs@s_plugin ] }, 04 { types: [ Configs@AppTheme, Configs@PluginTheme ] }



]



}



第23页

轻/轻盈产出/arsc分离



想象中最简单的分离方式

host (0x7f) |-- mipmap (02) | |-- ic_launcher (0000) | `-- values |-- strings.xml (03) | |-- app_name (0000) | `-- syles.xml (04) |-- AppTheme (0000)



plugin (0x7f)

|-- mipmap (02) | |--padding_mipmap_0000 | `-- ic_plugin (0001)

`-- values |-- strings.xml (03) | |-- padding_string_0000 | `-- s_plugin (0001) `-- syles.xml (04) |-- padding_style_0000 `-- PluginTheme (0001)



存在问题:必须补齐资源(输出变大)、只能分离一个插件



第24页

轻/轻盈产出/arsc分离

实践中最极致的分离方式

host (0x7f) |-- mipmap (02) | |-- ic_launcher (0000) | `-- values |-- strings.xml (03) | |-- app_name (0000) | `-- syles.xml (04) |-- AppTheme (0000)



plugin ( 0x7e )

|-- mipmap (02)

|| | `-- ic_plugin (0000 )

`-- values |-- strings.xml (03)

|| | `-- s_plugin ( 0000 ) `-- syles.xml (04)

| `-- PluginTheme ( 0000 )



第25页

轻/轻盈产出



HOST



0x7e



0x7d



7c



第26页

轻/轻度Hook



方法A Hook A

方法B

一个对象



我是一个Hook

我重写一个「对象」的「方法」

让她忘了从前



第27页

轻/轻度Hook



方法A Hook A

方法B

一个对象



但是首先 我要找到她

在我的「进程」里 她「静态」的坐着 她的方法向我「开放」



第28页

轻/轻度Hook



我的「进程」

com.user.galen

启动 插件Activity



第29页

轻/轻度Hook



我的「进程」

com.user.galen

启动 插件Activity



系统进程

system.process

Intent解析 任务栈调度 Activity栈调度



我的「进程」

com.user.galen

实际启动 插件Activity



第30页

轻/轻度Hook



我的「进程」

com.user.galen

启动 插件Activity



系统进程

system.process

Intent解析 任务栈调度 Activity栈调度



我的「进程」

com.user.galen

实际启动 插件Activity



第31页

轻/轻度Hook



我的「进程」

com.user.galen



启动 插件Activity



Hook 伪装宿主



系统进程

system.process

Intent解析 任务栈调度 Activity栈调度



我的「进程」

com.user.galen

实际启动 插件Activity



第32页

轻/轻度Hook



我的「进程」

com.user.galen



启动 插件Activity



Hook 伪装宿主



系统进程

system.process

Intent解析 任务栈调度 Activity栈调度



我的「进程」

com.user.galen



Hook 还原插件



实际启动 插件Activity



第33页

轻/轻度Hook



实际启动 插件Activity



Small Droid Plugin



private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

// 创建Activity if (r.activityInfo.targetActivity != null) {

component = new ComponentName(r.activityInfo.packageName,

r.activityInfo.targetActivity) ; } java.lang.ClassLoader cl = r.packageInfo.getClassLoader();

activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent);



Android-PluginFramework ACDD



// 绑定Context Context appContext = createBaseContextForActivity(r, activity);

activity.attach(appContext, this, getInstrumentation(), ...); // 设置主题

int theme = r.activityInfo.getThemeResource(); if (theme != 0) {

activity.setTheme(theme);

}



Dynamic-Load-APK Direct-Load-APK



// 触发onCreate mInstrumentation.callActivityOnCreate(activity, r.state); }



第34页

轻/轻度Hook



插件方案



代表框架



包数



Droid Plugin



1/插件



完全隔离 Dynamic-Load-APK 1



宿主插件 两两融合

除主题外 完全融合

完全融合



Direct-Load-APK Android-Plugin-

Framework ACDD

Small



1 1 1 1



类加载器 资源管理器



个数



个数



Context



1/插件



1/插件



1/插件



1/插件 1/插件 1/插件 1 1



1/插件 1/插件 1/插件 1 1



1/插件Activity 1/插件Activity 1/插件Activity 1/插件Activity 1



第35页





IDE友好 @Debug



模块变身 @Release



第36页

巧/IDE友好

支持创建插件模块 支持编译插件模块 支持插件模块间依赖

支持联合调试



第37页

巧/IDE友好

app



app.*



web.*



lib.* lib.*



第38页

巧/IDE友好



vendor



app



vendor



app.*



lib.*



web.*



vendor



lib.*



vendor



lib.*



第39页

巧/模块变身 模块是开发态,插件是目标态。



模块



开发态



目标态



app.* lib.* [other].*



Application模块 可以依赖其他模块、可以独立运行

Library模块 可以被app.*依赖

Application模块 可以独立运行



带代码、资源的插件 带代码、资源的插件

仅含assets的插件



转换难点

AAR(代码/资源) 剥离

资源ID锁定



第40页

巧/模块变身



dependencies { provided fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.2.1' compile 'com.android.support:design:23.2.1'

}

app.main `-- build/intermediates/exploded-aar `-- com.android.support/appcompat-v7/23.2.1



classes.jar res/*



*.class



dex

classes.dex



res/*



aapt



arsc res/*



AAR



第41页

巧/模块变身

dependencies { provided fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.2.1' compile 'com.android.support:design:23.2.1'

}

app.main `-- build/intermediates/exploded-aar `-- com.android.support/appcompat-v7/23.2.1



AAR



classes.jar res/*



*.class



dex

classes.dex



res/*



aapt



arsc res/*



Small



arsc res/*



第42页

总结



dependencies { provided fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.2.1'

compile 'com.android.support:design:23.2.1' }



app`-.-mbauinild/intermedi•ateIsD/exEp多lod e模d-a块ar `-- com.andro•id公.sup共por库t/app依com赖pat-v7/23.2.1



编译时分离

• PP分段 • AAR分离



• 并入宿主 • 轻度Hook



开发时聚合



classes.jar



*.class



dex 运行时融合 classes.dex



res/*



res/*



aapt



arsc Small arsc



res/*



res/*



第43页

TODO



• IDE多模块 • 公共库依赖



编译按时需分加离载

• PP分段 • AAR分离



开发时聚合

xib级别的warm swap



iOS插件化 App Store布





插件间依赖关系

• 并入宿主 • 轻度Hook

运行时融合



第44页

Q &A

Small@wequick GalenLin



支持文件格式:*.pdf
上传最后阶段需要进行在线转换,可能需要1~2分钟,请耐心等待。