关键词:
前言
small是android与iOS平台比较出名的轻巧的跨平台插件化框架,也正是被这一点吸引,决定将small应用到集团内部的应用引擎模块化方案中,本篇博文主要讲述本人基于small在android平台实现的定制化APP方案(运营自由配置、自由组合、自动打包)~
框架解决问题
- 由于公司业务的发展,导致更多的超级app诞生于世,导致app 项目太大、耦合严重,且相关开发人员相互耦合,导致效率低下
- app 热修复问题在很多场景是急需的
- 对于开发效率方面,采用了weex模块进行快速迭代
在介绍框架之前首先熟悉一下small的原理~
原理介绍
small 插件化方案分为两个步骤
- gradle 打包插件机制
- 运行期加载机制
打包插件机制
将多个app与lib工程编译成so文件
运行期加载机制
Dynamic load classes
DexClassLoader不支持”.so”后缀,为了让应用启动时能自动复制插件包到应用存储目录,需要支持”.so”后缀。做法就是模拟 压缩包加载代码块,创建一个dex元素,再反射添加到宿主class loader里的dexPathList。
Dynamic load resources
Dynamic register activities
activity 启动过程:
注: Android activities受Instrumentation监控
- 由Activity的startActivityForResult方法启动,通过instrumentation的execStartActivity方法激活生命周期。
- 在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创建实例
@Override
public Activity newActivity(ClassLoader cl, String className, Intent intent)
className = restoreToReal(intent, className);
return base.newActivity(cl, className, intent);
项目构建
按照官方的教程,初始化成功之后,项目结构如下:
框架获取
- git clone https://github.com/osmartian/odyssey.git
- cd odyssey
- 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:
// 框架模块uri
uri: 'bottom',
// 可选
tags: []
,
// 配置small打包配置
modules:
// small 版本
version: '1.0.0',
// 需要打包的app及lib
bundles: [
uri: 'bottom',
pkg: 'com.osmartian.small.app.bottom'
,
...
uri: 'lib.style',
pkg: 'com.osmartian.small.lib.style'
]
APK生成过程
- 动态修改APP基本信息
采用动态修改gradle配置方式,修改AppID、appName、appIcon…
在项目根build.gradle中有如下配置,只需动态修改此配置即可:
ext
compileSdkVersion = 25
buildToolsVersion = '25.0.2'
applicationId = "com.syswin.toon.walid"
appName = "Walid APK"
appIcon = "top"
minSdkVersion = 15
targetSdkVersion = 25
versionCode = 10
versionName = "1.0.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";
- 生成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
- 执行small打包 -> so 文件
将需要打包的模块打包成so文件
npm run build:small
- 编译生成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
超市商场app软件定制解决方案
...吸引下,很多传统电商开始转型,实现平台化发展,开发定制APP软件,主要以线下线上发展模式为主,与实体店发展互补,获得新的生存机会。650)this.width=650;"src="http://www.summersoft.net//upload/image/20170124/148522535668202491 查看详情
weex技术剖析
...微软的Cordova相比,Weex更加轻量,体积小巧。因为基于webconponent标准,使得开发更加简洁标准,方便上手。Native组件和API都可以横向扩展,方便根据业务灵活定制。Weex渲染层具备优异的性能表现, 查看详情
hadoopha高可用原理及部署
...FileSystem)在QJM出现之前,为保障集群的HA,设计的是一种基于NAS的共享存储机制,即主备NameNode间通过NAS进行元数据的同步。该方案有什么缺点呢,主要有以下几点:1.定制化硬件设备:必须是支持NAS的设备才能满足需求2.复杂化... 查看详情
weex环境配置快速上手
...微软的Cordova相比,Weex更加轻量,体积小巧。因为基于webconponent标准,使得开发更加简洁标准,方便上手。Native组件和API都可以横向扩展,方便根据业务灵活定制。Weex渲染层具备优异的性能表现,能够跨平... 查看详情
githubcodespaces使用及定制化(代码片段)
GithubCodeSpaces使用及定制化IntroGithub最近推出了很多令人兴奋的新功能,最近使用了GithubCodeSpaces,觉得还是挺不错的,CodeSpaces相当于自己有了一个云主机,真正实现了云端开发,CodeSpaces和Github做了很好的集成... 查看详情
硬件加速及定制化
在过去的一年中,我们可以看到多媒体特别是音视频技术的能力在严峻的挑战下,为各行各业带来了巨大的变化。疫情过后,又会有哪些多媒体新技术、新实践呈现在大众的视野当中?为行业的发展与应用带来哪... 查看详情
app项目如何与插件化无缝结合
...log.csdn.net/u011176685/article/details/52006474上面一篇主要介绍了Small的原理,相信大家应该现在心里有个大概的了解。好,我们接下来继续开始!一、Small的使用关于Small的使用,Small的使用这里讲的很详细,关于这里... 查看详情
基于rocketmqprometheusexporter打造定制化devops平台
本文将对RocketMQ-Exporter的设计实现做一个简单的介绍,读者可以通过本文了解到RocketMQ-Exporter的实现过程,以及通过RocketMQ-Exporter来搭建自己的RocketMQ监控系统。该项目的git地址https://github.com/apache/rocketmq-exporter文章主要内容包含以... 查看详情
es-修改分词器及定制分词器
参考技术A修改分词器设置启用stardar停用词tokenfilter,在stardard中stoptokenfilter是默认被禁用的定制化自己的分词器在指定的type里面用定制化的分词器 查看详情
混合开发之uni-app
...完整App,并提供原生插件的市场交易和云打包。这些组合方案,开发者切实的提高效率、降低成本。如果你是web前端,不熟悉weex,那么建议你仍然以使用vue为主,在App端某些vue表现不佳的场景下使用nvue作为强化补充:uni-appApp端... 查看详情
快手基于flink构建实时数仓场景化实践
简介: 一文了解快手基于Flink构建的实时数仓架构,以及一些难题的解决方案。本文整理自快手数据技术专家李天朔在5月22日北京站FlinkMeetup分享的议题《快手基于Flink构建实时数仓场景化实践》,内容包括:快... 查看详情
平台化与数据驱动—行业(私有)云安全解决方案实践
基于海量数据的主动挖掘,引入机器智能学习算法,挖掘安全威胁,人工智能辅助进行安全决策利用SDN、NFV技术打造云计算安全平台,实现云环境内安全能力的横向弹性扩展,纵向基于业务系统的灵活定制。完整PPT材料以及更多... 查看详情
平安保险基于spi机制的rocketmq定制化应用
第二点,业务系统的使用场景会特别多,使用场景广泛带来的问题就是会创建大量的topic,所以这时候就得去衡量消息中间件在多topic场景下性能是否能满足需求。我自己在测试的时候呢,用1K的消息随机往1万个topic写数据,单bro... 查看详情
《自适应路由服务合成:模型及优化》
...为应用合成定制化的路由服务,满足用户差异化的需求。基于网络功能虚拟化和SDN提出了一种自适应路由服务合成机制。机器学习起的作用:运用多层前馈神经网构建路由服务离线模式和在线模式两阶段学习模型,对路由功能选... 查看详情
定制化azure站点java运行环境
Java8下PermGen及参数设置?在上一章节中,我们定制化使用了Java8环境,使用我们的测试页面打印出了JVM基本参数,但如果我们自己观察,会发现在MXBeans中,没有出现PermGen的使用数据,初始大小等信息,即使我们已经设置了大小: ... 查看详情
基于weex的flutter项目框架
...说,给出了更好的跨平台解决方案。所以我们设计了一套基于Weex实现,底层跑在FlutterEngine上的框架。 底层的Runtime采用isolateengine,框架业务逻辑,Dom的解析逻辑和Render逻辑都跑在这里。 渲染引擎采用Flutter的Skia,彻底剥... 查看详情
基于rocketmqprometheusexporter打造定制化devops平台
本文将对RocketMQ-Exporter的设计实现做一个简单的介绍,读者可以通过本文了解到RocketMQ-Exporter的实现过程,以及通过RocketMQ-Exporter来搭建自己的RocketMQ监控系统。该项目的git地址https://github.com/apache/rocketmq-exporter文章主要内容包含以... 查看详情
weex环境搭建及组件相关使用总结
...始化请确保你已经安装了 Node.js,然后全局安装 weex-cli。npminstallweex-toolkit-g这条命令会向你命令行环境中注册一个 weex 命令。你可以用 weexcreate 命令来创建一个空的模板项目:weexcreateawesome-app命令执行完以... 查看详情