前言

small是android与iOS平台比较出名的轻巧的跨平台插件化框架,也正是被这一点吸引,决定将small应用到集团内部的应用引擎模块化方案中,本篇博文主要讲述本人基于small在android平台实现的定制化APP方案(运营自由配置、自由组合、自动打包)~

框架解决问题

  1. 由于公司业务的发展,导致更多的超级app诞生于世,导致app 项目太大、耦合严重,且相关开发人员相互耦合,导致效率低下
  2. app 热修复问题在很多场景是急需的
  3. 对于开发效率方面,采用了weex模块进行快速迭代

在介绍框架之前首先熟悉一下small的原理~

原理介绍

small 插件化方案分为两个步骤

  1. gradle 打包插件机制
  2. 运行期加载机制

打包插件机制

官方说明

将多个app与lib工程编译成so文件

运行期加载机制

Dynamic load classes

官方说明

DexClassLoader不支持”.so”后缀,为了让应用启动时能自动复制插件包到应用存储目录,需要支持”.so”后缀。做法就是模拟 压缩包加载代码块,创建一个dex元素,再反射添加到宿主class loader里的dexPathList。

Dynamic load resources

官方说明

Dynamic register activities

activity 启动过程:

注: Android activities受Instrumentation监控

  1. 由Activity的startActivityForResult方法启动,通过instrumentation的execStartActivity方法激活生命周期。
  2. 在ActivityThread的performLaunchActivity方法中通过instrumentation的newActivity方法实例化。
small 实现方案:

1. 首先在宿主manifest中注册一个命名特殊的占坑activity

<!-- Stub Activities -->
<activity android:name=".A.0" android:launchMode="standard"/>

2. 封装一个instrumentation,替换掉宿主的

(1)、欺骗startActivityForResult(启动过程1)以获得生命周期
(2)、欺骗performLaunchActivity(启动过程2)来创建插件activity实例

ActivityThread thread = currentActivityThread();
Instrumentation base = thread.@mInstrumentation;
Instrumentation wrapper = new InstrumentationWrapper(base);
thread.@mInstrumentation = wrapper;class InstrumentationWrapper extends Instrumentation {// 欺骗startActivityForResult获得生命周期public ActivityResult execStartActivity(..., Intent intent, ...) {fakeToStub(intent);base.execStartActivity(args);}// 欺骗performLaunchActivity创建实例@Overridepublic Activity newActivity(ClassLoader cl, String className, Intent intent) {className = restoreToReal(intent, className);return base.newActivity(cl, className, intent);}
} 

项目构建

按照官方的教程,初始化成功之后,项目结构如下:

框架获取

  1. git clone https://github.com/osmartian/odyssey.git
  2. cd odyssey
  3. npm install

项目结构

small-frame
├── app (宿主app)
│      ├── LaunchActivity
│      │
│      └── SmallApp
│
├── app.top (topbar框架APP)
│      │
│      └── MainActivity
│
├── app.bottom (bottombar框架app)
│      │
│      └── MainActivity
│
├── app.home (首页模块app)
│      └── MainFragment
│
├── app.weex (weex模块app)
│      │
│      ├── MainActivity
│      │
│      └── MainFragment
│
├── app.detail (详情模块app)
│      ├── MainActivity
│      │
│      └── SubActivity
│
├── lib.weex (weex lib 库)
│
├── lib.martian (公共工具库)
│
└── lib.style (公共样式库)└── res├── colors.xml├── dimens.xml└── styles.xml

config驱动文件打包APK流程

打包配置说明

{// app基本信息配置baseInfo: {applicationId: 'com.syswin.toon.bottom',versionCode: 2,appIcon: 'bottom',appName: 'BOTTOM框架',versionName: '1.0.1'},// 框架末班配置frame: {// 框架模块uriuri: 'bottom',// 可选tags: []},// 配置small打包配置modules: {// small 版本version: '1.0.0',// 需要打包的app及libbundles: [{uri: 'bottom',pkg: 'com.osmartian.small.app.bottom'},... {uri: 'lib.style',pkg: 'com.osmartian.small.lib.style'}]}
}

APK生成过程

  1. 动态修改APP基本信息

采用动态修改gradle配置方式,修改AppID、appName、appIcon…

在项目根build.gradle中有如下配置,只需动态修改此配置即可:

ext {compileSdkVersion = 25buildToolsVersion = '25.0.2'applicationId = "com.syswin.toon.walid"appName = "Walid APK"appIcon = "top"minSdkVersion = 15targetSdkVersion = 25versionCode = 10versionName = "1.0.1"
}
  1. 设置框架frame模块

动态设置框架模块uri,用于宿主模块调起

见宿主app模块下com.osmartian.small中的config.java文件:

package com.osmartian.small;/*** @Author : walid* @Data : 2017-03-14  22:36* @Describe : INDEX URL配置*/
public class Config {public static final String INDEX_URI = "bottom?tags=%5B%7B%22name%22%3A%22%E9%A6%96%E9%A1%B5%22%2C%22uri%22%3A%22home%22%7D%2C%7B%22name%22%3A%22%E6%88%91%E7%9A%84%22%2C%22uri%22%3A%22weex%3Furl%3Dhttp%253A%252F%252F172.31.243.44%253A12580%252Fdist%252Fweex%252Fviews%252Fmine%252Fapp.js%22%7D%2C%7B%22name%22%3A%22%E4%B8%AA%E4%BA%BA%E8%B5%84%E6%96%99%22%2C%22uri%22%3A%22weex%3Furl%3Dhttp%253A%252F%252F172.31.243.44%253A12580%252Fdist%252Fweex%252Fviews%252Fuserinfo%252Fapp.js%22%7D%5D";
}
  1. 生成bundle.json small打包需要文件

动态生成bundle.json small打包文件,且copy到android、ios项目

(1)、生成bundle.json文件

const bundlePath = path.join(__dirname, '../../build/output', 'bundle.json')// 框架模块安装
function packModules(modules) {console.log(modules)return new Promise((resolve, reject) => {fs.writeFile(bundlePath, JSON.stringify(modules), (err) => {err ? reject(err) : resolve()})})
}

(2)、copy 至 android 、 ios项目

// cp -vf build/output/bundle.json android/app/src/main/assets/bundle.json
npm run copy:bundle
  1. 执行small打包 -> so 文件

将需要打包的模块打包成so文件

npm run build:small
  1. 编译生成apk文件

执行npm指令进行apk生成

npm run dev:android
// 或
npm run build:android

small 模块跳转操作

1、 跳转h5

  Small.openUri("https://github.com/osmartian/small-frame", getContext());

2、 跳转app module 传值

  Small.openUri("detail?params=我是参数,从首页传送过来的~", getContext());

3、 跳转app module 二级界面

  Small.openUri("detail/sub", getContext());

项目打包APK示例

打包topbar框架APK

  • config 文件配置
{baseInfo: {applicationId: 'com.syswin.toon.top',versionCode: 2,appIcon: 'top',appName: 'TOP框架',versionName: '1.0.1'},frame: {uri: 'top',tags: [{name: '首页',uri: 'home'},{name: '发起筹款',uri: `weex?url=${encodeURIComponent(`http://${ipAddress}:12580/dist/weex/views/launch/app.js`)}`},{name: '我的',uri: `weex?url=${encodeURIComponent(`http://${ipAddress}:12580/dist/weex/views/mine/app.js`)}`}]},modules: {version: '1.0.0',bundles: [{uri: 'top',pkg: 'com.osmartian.small.app.top'},{uri: 'home',pkg: 'com.osmartian.small.app.home'},{uri: 'weex',pkg: 'com.osmartian.small.app.weex'},{uri: 'lib.weex',pkg: 'com.osmartian.small.lib.weex'},{uri: 'lib.martian',pkg: 'com.osmartian.small.lib.martian'},{uri: 'lib.style',pkg: 'com.osmartian.small.lib.style'}]}
}

示例图片

打包bottombar框架APK

  • config 文件配置
{baseInfo: {applicationId: 'com.syswin.toon.bottom',versionCode: 2,appIcon: 'bottom',appName: 'BOTTOM框架',versionName: '1.0.1'},frame: {uri: 'bottom',tags: [{name: 'Weex首页',uri: `weex?url=${encodeURIComponent(`http://${ipAddress}:12580/dist/weex/views/home/app.js`)}`},{name: '原生首页',uri: `home`},{name: '我的',uri: `weex?url=${encodeURIComponent(`http://${ipAddress}:12580/dist/weex/views/mine/app.js`)}`}]},modules: {version: '1.0.0',bundles: [{uri: 'bottom',pkg: 'com.osmartian.small.app.bottom'},{uri: 'home',pkg: 'com.osmartian.small.app.home'},{uri: 'weex',pkg: 'com.osmartian.small.app.weex'},{uri: 'detail',pkg: 'com.osmartian.small.app.detail',rules: {sub: 'Sub'}},{uri: 'lib.weex',pkg: 'com.osmartian.small.lib.weex'},{uri: 'lib.martian',pkg: 'com.osmartian.small.lib.martian'},{uri: 'lib.style',pkg: 'com.osmartian.small.lib.style'}]}
}

示例图片

结语

至此,基于small的定制化APP方案介绍完毕了,此方案还是雏形阶段,也希望业界朋友多多点评、多多吐槽,也希望大家前去start及提一些各自的建议。

项目地址:https://github.com/osmartian/odyssey.git

基于Small及Weex的定制化APP方案相关推荐

  1. 基于 RocketMQ Prometheus Exporter 打造定制化 DevOps 平台

    作者 | 陈厚道  冯庆 来源 | 阿里巴巴云原生公众号 导读:本文将对 RocketMQ-Exporter 的设计实现做一个简单的介绍,读者可通过本文了解到 RocketMQ-Exporter 的实 ...

  2. 精品基于Uniapp+SSM实现的定制旅游APP

    <[含文档+PPT+源码等]精品基于Uniapp+SSM实现的定制旅游APP[包运行成功]>该项目含有源码.文档.PPT.配套开发软件.软件安装教程.项目发布教程等 软件开发环境及开发工具 ...

  3. 高度可定制化的方案_如何开发高度可定制的产品

    高度可定制化的方案 您是否听说过:"我们非常喜欢您的产品--除了一些小细节."? 然后,CIO推出了一系列其他"必备"要求的清单,其中有数百个要添加到您的惊人产 ...

  4. .NET Core开发实战(第14课:自定义配置数据源:低成本实现定制化配置方案)--学习笔记...

    14 | 自定义配置数据源:低成本实现定制化配置方案 这一节讲解如何定义自己的数据源,来扩展配置框架 扩展步骤 1.实现 IConfigurationSource 2.实现 IConfiguratio ...

  5. 平安保险基于 SPI 机制的 RocketMQ 定制化应用

    作者:孙园园|平安人寿资深开发 为什么选用 RocketMQ 首先跟大家聊聊我们为什么会选用 RocketMQ,在做技术选型的过程中,应用场景应该是最先考虑清楚的,只有确定好了应用场景在做技术选型的过 ...

  6. android studio项目实例基于Uniapp+SSM实现的定制旅游APP

  7. 计算机毕业设计安卓App毕设项目之ssm定制旅游APP

    目录 一.项目介绍 二.文档截图 三.运行截图 一.项目介绍 含文档+PPT+源码等]精品基于Uniapp+SSM实现的定制旅游APP[包运行成功]>该项目含有源码.文档.PPT.配套开发软件. ...

  8. 服务器定制化—服务器行业发展的新驱动力

    虽说在人工智能.边缘计算.云计算等为代表的新数据时代的大背景下,企业的数字化进程离不开服务器算力的支撑,但由于服务器市场已经相对成熟,格局基本形成. 因此在X86服务器行业中,鲜有大事发生,各服务器品 ...

  9. android 圆角边框边框渐变,Android深度定制化TabLayout:圆角,渐变色,背景边框,圆角渐变下划线,基于Android原生TabLayout...

    Android深度定制化TabLayout:圆角,渐变色,背景边框,圆角渐变下划线,基于Android原生TabLayout 在附录1的基础上丰富自定义的TabLayout,这次增加两个内容: 1,当 ...

最新文章

  1. Python数据挖掘:数据探索,数据清洗,异常值处理
  2. ubuntu12.04 alternate win7 双系统安装
  3. 怎么讲d 盘里的软件弄到桌面_教大家电脑怎么把e盘文件移到d位置
  4. [trustzone]-ARMV8的aarch64和aarch32环境下ELx级别的理解
  5. jzoj6276-[Noip提高组模拟1]树【线段树,扫描线,倍增】
  6. 街篮混服服务器信息,街篮手游闻鸡起舞服务器火爆开启
  7. WordPress博客网站搬家和换域名方法
  8. selenium常用方法
  9. 我的博客面貌焕然一新
  10. 二分法01:查找一个数
  11. 并发编程 - io模型 - 总结
  12. 我不曾忘记的初心-大厂小厂
  13. If,for,range混合使用笔记-(VBA视频教程2:使用IF进行逻辑判断)
  14. App Store审核标准
  15. 【技能】快递管家无需开发集成金蝶云星辰示例
  16. form表单Get方式提交时,action中带参数传递不了
  17. matlab 变量的定义变量名称,matlab定义变量名
  18. web多媒体技术在视频编辑场景的应用
  19. 速途网范锋:重要合作可能决定网络企业生死
  20. Freemarker导出word图片不显示可能的原因

热门文章

  1. 日常常用英文单词整理
  2. win10 激活方式
  3. 网络安全系列-五十一:网络流量威胁监测系统的方案选择
  4. 西门子触摸屏脚本程序_西门子触摸屏利用VBScript脚本创建csv文件
  5. Allure环境部署与生成+Allure内容增强
  6. touch - 修改文件的时间戳记.
  7. 2020年,iOS开发面试跳槽(必看攻略)
  8. 中国移动10086客服中心工作人员的血和泪
  9. 【智能决策引擎】规则引擎介绍
  10. 美国人在家用计算机访问网络,美国人在家里请客往往有两种方式