theme: channing-cyan highlight: a11y-dark
整体架构
这里首先来看下凡泰小程序的总体架构图(关注公众号获取白皮书):
宿主APP:和插件化中的宿主类似,只是提供了一个小程序的运行环境(插件化是模拟提供了一个Android系统的运行环境)。需集成SDK,在适当时机初始化SDK。并加载指定小程序(小程序唯一标识APPID)
小程序开发团队:负责开发小程序(类似微信小程序开发),发布代码包版本,提交审核
运营团队:对小程序进行审核,上下架版本,对SDK进行数字签名以保证宿主使用的SDK是未污染,最新,及安全的
SDK运行时:
- 提供安全沙箱,保护沙箱中的 H5 应用和小程序应用不被宿主 App 干扰
- 提供在宿主 App 内安全执行小程序/H5 应用的环境
- 指标采集,应用性能指标(APM)采集
后端服务:也就是正常的接口请求
对应的流程图:
优势
- SDK内部代码运行在封闭的安全沙箱中,不会造成数据外泄
- 在Android,SDK内部使用的内核上与系统浏览器的内核不一样
- 无需发版即可新增小功能,快速试错迭代(虽说热修复也可以完成,但代价太高)
- 轻量级,一次编写即可接入到不同的平台上(这也是小程序有的优势)
- 业务功能发布需服务器端进行审核发布,可提供给多家客户使用
- 相比于纯h5方案,渲染不基于DOM而是WebView堆栈中的实例间切换。Android端采用性能更高的Chromium。
实践
流程
使用IDE开发小程序提交版本----》服务器端审核通过,并添加可使用该小程序的应用----》应用也就是宿主集成SDK-----》应用在合适时机初始化SDK并加载对应的小程序版本(由运营人员提供)----》SDK内部检测环境是否安全及正规并创建沙箱和SDK内部代码执行的平台-----》通过SDK内部上传数据运营人员收集到APM进行优化小程序
创建小程序
点击右上角的编辑按钮即可完善小程序的详情内容
上传代码包
有两种方式:
- 一种是通过IDE上传编译后的代码包
- 一种是未经编译的代码包
未经编译的代码包需在上传时云端编译
我这里上传一份错误的zip包,可以看到会显示下图:
- 1.0.0选择的上传类型是未经编译的代码包,其会在云端编译并显示编译结果
- 1.0.1选择的上传类型是已经经过的编译代码包,无需编译并可直接下载代码包
借助IDE上传经过编译后的代码包
FIDE 使用说明文档 FIDE 下载链接 可在IDE中完成小程序的 API 和页面的开发调试、代码查看和编辑、小程序预览和发布等功能。
IDE绑定小程序的appid
需要登录IDE(使用登录网页版的手机号即可自动关联该账号下的小程序appid),App ID下拉框会自动显示该账号下创建的小程序appid,点击完成即可。
选择对应移动端平台的模拟器会重新编译整个项目:
编译完成后可以看到如下内容:
- 视图框架
- 日志打印(支持级别)
- 网络状况
- 切换模拟器后的编译日志
IDE上传代码包
点击确定后会看到下图:
这个就是利用IDE上传代码包的步骤,刷新网页再次查看版本记录可以看到新版本的提交记录:
审核提交的代码版本
详情往下翻可以看到审核Tab,点击新增审核,选择审核版本
填写审核的详情内容
点击提交,即可看到审核的历史记录:
体验版本无需审核
还有一种可以快速查看效果的方式无需等待审核通过即可体验:
利用凡泰助手或者App扫码即可运行该版本的小程序进行测试:
也可以在小程序上架审核栏中通过浏览器来预览/选择同意通过该版本发布
创建服务器端应用
在应用管理一栏中,点击新增合作应用并保存
注意,一个账号仅可免费关联十个应用,谨慎使用
关联应用
添加应用相关的Bundle ID,以获取SDK的KEY和对应密钥。
Android平台为清单文件中的package属性,ios平台需登录开发者平台去获取BundleId
关联成功后会有如下提示:
宿主应用必须写入对应SDK KEY与SDK SECRET,方可访问该小程序,有如下内容需要注意:
- 应用必须集成 FinClip 小程序运行时SDK,并配置对应的SDK key和secret;
- 需要将上架的小程序与合作应用关联,才能打开对应的小程序;
- 小程序开放平台将校验SDK KEY与应用Bundle ID及小程序的关联关系,如果未关联将无法获取对应小程序;关联小程序 点击关联小程序
点击新增关联:
这里我们选择上面审核通过的小程序版本
关联成功有如下提示:
创建应用
上面在关联应用时已经关联了一个应用,我们用这个应用来开发:
集成SDK
项目根目录build.gradle中添加如下代码:
代码语言:javascript复制maven {
url "https://gradle.finogeeks.club/repository/applet/"
credentials {
username "applet"
password "123321"
}
}
代码语言:javascript复制//kotlin插件
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.1"
SDK集成页面汇总最新版SDK为2.36.7,这里使用最新版本的sdk:
代码语言:javascript复制implementation 'com.finogeeks.lib:finapplet:2.36.7' //具体的版本号
SDK中的动态库是被加固过的,被加固过的动态库在编译打包时不能被压缩,否则加载的时候会报错。
因此在android闭包下面还需加入这项配置:
代码语言:javascript复制packagingOptions {
// libsdkcore.so、libyuvutil.so是被加固过的,不能被压缩,否则加载动态库时会报错
doNotStrip "*/x86/libsdkcore.so"
doNotStrip "*/x86_64/libsdkcore.so"
doNotStrip "*/armeabi/libsdkcore.so"
doNotStrip "*/armeabi-v7a/libsdkcore.so"
doNotStrip "*/arm64-v8a/libsdkcore.so"
doNotStrip "*/x86/libyuvutil.so"
doNotStrip "*/x86_64/libyuvutil.so"
doNotStrip "*/armeabi/libyuvutil.so"
doNotStrip "*/armeabi-v7a/libyuvutil.so"
doNotStrip "*/arm64-v8a/libyuvutil.so"
}
配置混淆规则:
代码语言:javascript复制-keep class com.finogeeks.** {*;}
初始化sdk
在Application中进行初始化(记得配置清单文件):
代码语言:javascript复制package com.example.finclipdemo
import android.app.Application
import android.util.Log
import com.finogeeks.lib.applet.client.FinAppClient
import com.finogeeks.lib.applet.client.FinAppConfig
import com.finogeeks.lib.applet.interfaces.FinCallback
class FinClipApp : Application() {
override fun onCreate() {
super.onCreate()
if (FinAppClient.isFinAppProcess(this)) {
//小程序进程,不需要进行SDK初始化工作
return
}
val config: FinAppConfig = FinAppConfig.Builder()
.setAppKey("M8j6KLAGGce/g0XJB8hlqdCjvGiQNVy6ijJ2n9FVbD4=")
.setAppSecret("306cf806a6ba433a")
.setApiUrl("https://api.finclip.com")
.setApiPrefix("/api/v1/mop/")
.setGlideWithJWT(false)
.build()
val callback: FinCallback<Any?> = object : FinCallback<Any?> {
override fun onSuccess(p0: Any?) {
// SDK初始化成功
Log.i("TAG", "onSuccess: SDK初始化成功")
}
override fun onError(p0: Int, p1: String?) {
// SDK初始化失败
Log.i("TAG", "onError: SDK初始化失败")
}
override fun onProgress(p0: Int, p1: String?) {
//SDK正在初始化
Log.i("TAG", "onProgress: SDK正在初始化....")
}
}
//初始化SDK
FinAppClient.init(this, config, callback)
}
}
SDK 采用多进程机制实现,每个小程序运行在独立的进程中,即一个小程序对应一个进程。因此代码中需要将不需要在小程序中进行的操作进行省略(内部通过是否为宿主进程实现)
使用小程序
代码语言:javascript复制//startApplet第二个参数为小程序的APP ID
//启动小程序方式一:
FinAppClient.appletApiManager.startApplet(this, "628a6376be244600011af03c")
//启动小程序方式二:跳转到指定小程序页面内部指定路径
val params: MutableMap<String, String> = HashMap()
// path为小程序页面路径
params["path"] = "/pages/index/index"
// query为启动参数,内容为"key1=value1&key2=value2 ..."的形式
params["query"] = "aaa="test"&bbb="123""
FinAppClient.appletApiManager.startApplet(this, "628a6376be244600011af03c",params)
gif制作用的三方软件,jym有好用的软件可以推荐一下实在找不到了。 用的as自带的录屏,gif长达48s前面 黑屏部分是在AS在启动应用,后面一闪一闪的黑屏是操作中抖动特别严重(估计是在刷新)。
视频中可以看到如下:
- 启动应用后会有个明显的跳转,这是跳转到小程序界面了,也可以看到小程序初始化的转圈过程 明显的跳转:
小程序初始化界面:
- 进入后就是小程序的界面了:
点击右上角可以看到:
以及版本号,版本说明:
点击右上角关闭后会回到原生Activity界面:
- 关闭小程序右上角的X: 可以看到确实小程序是以单独进程运行的,所以就验证了我们之前所说的初始化SDK时要检测是否为宿主进程才去初始化
关闭后后续APP内还可以跳转到小程序页面
- 小程序单独运行(借助SDK沙箱) 即使宿主进程挂掉小程序也依然可以运行
使用FIDE的默认小程序页面,APP内部运行时支持图片,视频播放等功能:
更多体验内容请自行探索~~~
反馈
反馈几个问题:
- 可以看到gif中首次初始化会很卡,点击后页面快速闪
- 脱离宿主依然可以运行,用户在不知情的情况下还需要手动杀掉小程序的单独进程
- 跳转到小程序页面有时需要等待2-3s