开发

宿主接入文档

1 注册宿主信息

到小程序开源宿主平台注册宿主信息

宿主平台链接:https://ossunion.baidu.com/opensource/home/setting.html

2 宿主app包信息管理 & 获取宿主配置文件

2.1 宿主app包信息管理

在小程序开源宿主平台注册宿主app的包名签名信息(安卓支持配置多个包名签名),用于小程序安全下发

https://ossunion.baidu.com/opensourcedocs/introduction/principle/access/package/

2.2 获取宿主配置文件

  1. 登陆宿主平台,下载配置文件union-cfg.json
  2. 将配置文件union-cfg.json放到宿主工程的assets/config/目录下,无此路径新建即可。

3 配置小程序组件接入插件

由于小程序框架规模较大,组件模块众多,所以提供了一个 gradle 编译插件(Nest 插件),来简化小程序组件接入。

接入共分两步:

  1. 应用 Nest 插件并声明小程序框架版本号
  2. 配置线上小程序组件仓库的认证信息

3.1 应用 Nest 插件并声明小程序框架版本号

在宿主工程根目录的settings.gradle文件头中应用 Nest 插件并声明小程序框架版本号。

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 pluginManagement {
repositories {
// 1. 添加 Nest 插件所在的线上的仓库地址
maven { url "https://repository.smartapps.cn/repository/swan-mvn-nest-public" }
}
plugins {
// 2. 声明 Nest 插件及接入小程序框架的版本号,后续升级小程序框架,直接更新该版本号即可
id("com.baidu.swan.nest") version "2.91.0.100"
}
}
plugins {
// 3. 声明 Nest 插件 id,应用小程序接入插件 nest,使宿主工程能引用小程序组件,或者编译小程序源码
id("com.baidu.swan.nest")
}
// 下面可以正常声明宿主工程的其他模块
include ':app'

注:gradle 6.0 以下版本不支持pluginManagement{}语法块,可采用buildscript{}语法块方式接入,
参见本文章节”附2.1 兼容 gradle 6.0 以下版本“。

3.2 配置线上小程序组件仓库的认证信息

用于 Nest 插件访问小程序组件仓库所需的账户和认证信息,不同账户的认证信息具有不同的小程序组件仓库访问权限。支持在以下配置文件中任选其一进行配置:

  • 主要配置文件: ${宿主工程根目录}/swan.properties
  • 影子配置文件: ${宿主工程根目录}/.local.swan.properties (建议配置gitignore规则,避免提交至代码库)
  • 全局配置文件: ${编译机操作系统当前登陆用户的home目录}/.swan/swan.properties

示例如下:

1
2
3
# 小程序组件仓库认证信息
SWAN_REPO_USER=username # 小程序组件平台用户名,其值为开源宿主平台上的HostName字段
SWAN_REPO_PASS=password # 小程序组件平台密码,其值为开源宿主平台上的ApiKey字段
  • 注:宿主认证信息获取方法详见:宿主认证信息
  • 注:建议仓库认证信息不要在 【主要配置文件】 中直接配置,否则认证信息可能会提交至代码库,有泄漏风险。
  • 注:更多配置文件的介绍详见:构建参数配置(Swan-Prop)
  • 注:认证信息后面不要添加空格或其他内容

4 添加需要依赖的小程序组件

根据宿主需要,在宿主工程模块的build.gradle文件中配置需要依赖的小程序组件。

${宿主工程}/${宿主模块}/build.gradle 配置示例如下:

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
// 配置“deps.xxx.xxx”样式的小程序组件依赖引用 id,可以执行“./gradlew swanDeps”,查询小程序组件的引用 id 和状态
dependencies {
// 声明需要依赖的小程序组件

// 1.小程序与核心层
implementation deps.business.swan.core
// 2.小程序接口层
implementation deps.business.swan.facade
implementation deps.components.lib_empty_open
implementation deps.business.swan.open_impl

// 3.T7浏览内核依赖,二选一
//依赖T7浏览内核
implementation deps.business.swan.webview.sailor_so
implementation deps.business.swan.webview.so_lite
//不依赖T7浏览内核
//implementation deps.business.swan.webview.sailor

// 4.依赖地图组件
implementation deps.components.lib_map_full
// 5.依赖播放器组件
implementation deps.components.lib_videoplayer_impl

// 6.ipc框架依赖
implementation deps.service.lib_process_ipc
// 7.ioc框架依赖
implementation deps.basic.pyramid.annotation
// 8.聚合支付依赖,为宿主提供支付调起入口
implementation deps.business.components.lib_nuomi_pay.lib_nuomi_pay_core
implementation deps.business.components.lib_nuomi_pay.lib_pay

// 9.预置swan-js
implementation deps.business.swan.swan_js

}

注:如需使用更多组件依赖项,可参考”组件依赖id对照表“,在宿主工程中直接执行./gradlew swanDeps打印并查看所有小程序组件的信息,以便决定需要引入工程的小程序组件 id

5 配置依赖注入插件

${宿主工程}/${app模块}/build.gradle 配置示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 需要在apply plugin: 'com.android.application'之后添加
plugins { id 'com.android.application' }

// 如果宿主工程没有接入过scheme组件,那么还需要在app工程的build.gradle文件里添加如下配置:
apply plugin: 'com.baidu.pyramid.di'
apply plugin: 'com.baidu.scheme.scheme-classify'

// 配置依赖注入插件
pyramidConfig {
// 是否打开依赖注入
enable true
// 是否打开依赖注入插件的debug开关
debug false
// 是否应用增量编译模式
enableIncremental false
}

// 配置端能力描述表插件,不需要修改
schemeClassifyConfig {
// 端能力所属框架
schemeClassifyList = ['base', 'swan/v8', 'swan/webview', 'swan/web', 'empty', 'swan/v8_ab', 'swan/webview_ab',
"swan/lite"]
}

6 初始化小程序框架

在宿主工程的Application类中初始化小程序框架

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
class HostApp extends Application {

@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// 必须在attachBaseContext中初始化
SwanAppInitHelper.initContext(this);
}

@Override
public void onCreate() {
super.onCreate();

// 1.必须在attachBaseContext之后初始化

// 2.如果只希望在android5.0及以上系统使用小程序,使用以下函数初始化
// SwanAppInitHelper.onApplicationCreate(this, true);

// demo 默认打开5.0以下入口,即在安卓5.0以下也初始化小程序
SwanAppInitHelper.onApplicationCreate(this);
// 初始化小程序各模块,须保证在首次调起小程序之前至少调用一次
SwanAppInitHelper.tryInitModules();

// 如果使用了so后下载,可以使用此方式再合适的时机进行so的预下载
// SwanAppUtils.postOnUi(new Runnable() {
// @Override
// public void run() {
// SailorSoDownloadConfig.downloadSoSilent();
// }
// },3000);
}
}

7 Manifest配置

1
2
3
4
5
6
7
8
9
10
11
<application>
<!-- *****************以下是使用了百度地图时需要注册的信息*********************** -->

<!-- 使用百度定位SDK,则需要加此meta-data 第三方开发者必须自己到官网注册API_KEY,这里只是用作demo,使用了debug的签名 -->
<!-- 申请地址:https://lbsyun.baidu.com/index.php?title=androidsdk -->
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="GKjgLaVjrQnxqoBZm9VHCPSO8R4Nejqc" />
<!-- END LBS地图SDK -->

</application>

8 混淆文件(必须添加混淆文件,否则release包无法正常工作)

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
-keep public interface com.baidu.browser.core.INoProGuard
-keepattributes Exceptions,InnerClasses,Signature,*Annotation*
-keepclasseswithmembernames class * {
native <methods>;
}

-keep class * implements com.baidu.browser.core.INoProGuard {
*;
}

-keep class * implements com.baidu.searchbox.NoProGuard {
*;
}

-keep class * extends com.baidu.browser.core.INoProGuard {
*;
}

-keep class com.baidu.webkit.sdk.** {
*;
}

-keep interface com.baidu.webkit.sdk.** { *; }


-keep class com.baidu.browser.sailor.platform.nativeability.mime.** {
*;
}

-keepclassmembers class com.baidu.browser.sailor.** {
@android.webkit.JavascriptInterface <methods>;
}

-keep enum com.baidu.browser.sailor.BdSailorWebView* {
*;
}

-keep enum com.baidu.browser.sailor.BdSailorWebViewClientExt* {
*;
}
-keep enum com.baidu.browser.sailor.webkit.BdWebSettings* {
*;
}
-keep enum com.baidu.browser.sailor.BdSailorClient* {
*;
}
# Keep our interfaces so they can be used by other ProGuard rules.
# See http://sourceforge.net/p/proguard/bugs/466/
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip

# Do not strip any method/class that is annotated with @DoNotStrip
-keep @com.facebook.common.internal.DoNotStrip class *
-keepclassmembers class * {
@com.facebook.common.internal.DoNotStrip *;
}

# Keep native methods
-keepclassmembers class * {
native <methods>;
}

-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-dontoptimize

-useuniqueclassmembernames
# 增加行号
-keepattributes SourceFile,LineNumberTable
-ignorewarnings

# com.google.protobuf
-keep class com.google.protobuf.** { *; }
-keep interface com.google.protobuf.** { *; }

# com.baidu.webkit.sdk
-keep class com.baidu.blink.** { *; }
-keep interface com.baidu.blink.** { *; }
-keep class com.baidu.debuggerd.** { *; }
-keep interface com.baidu.debuggerd.** { *; }
-keep class com.baidu.dumper.** { *; }
-keep interface com.baidu.dumper.** { *; }
-keep class com.baidu.htmlNotification.** { *; }
-keep interface com.baidu.htmlNotification.** { *; }
-keep class com.baidu.webkit.sdk.** { *; }
-keep interface com.baidu.webkit.sdk.** { *; }

-keep class org.chromium.base.library_loader.** { *; }
-keep interface org.chromium.base.library_loader.** { *; }

# com.baidu.android.common.security
-keep class com.baidu.android.common.security.** { *; }
-keep interface com.baidu.android.common.security.** { *; }
# com.baidu.android.common.util
-keep class com.baidu.android.common.util.** { *; }
-keep interface com.baidu.android.common.util.** { *; }
-keep interface google.zxing.searchbox.** { *; }

# 保持@JavascriptInterface annotations 不被混淆掉

-keepattributes *JavascriptInterface*

-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}

# for UBC
-keep class com.baidu.ubc.UBC { *; }
-keep class com.baidu.ubc.Flow { *; }

# for lib-network
# okhttp & okio
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn org.conscrypt.**

-keep class okhttp3.**{ *; }
-keep class okio.**{ *; }
-keep class org.conscrypt.** { *; }
# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase

# searchbox http
-keep class com.baidu.searchbox.http.** { *; }

-keep @com.baidu.searchbox.v8engine.NotProguard class * {*;}
-keep,allowobfuscation @interface com.baidu.searchbox.v8engine.NotProguard
-keepclassmembers class * {
@com.baidu.searchbox.v8engine.NotProguard *;
}
-keepclassmembers class * {
@com.baidu.searchbox.v8engine.V8JavascriptField <fields>;
}

# rxjava
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
rx.internal.util.atomic.LinkedQueueNode consumerNode;
}

# 百度地图sdk的keep规则
-keep class com.baidu.android.bbalbs.common.** { *; }
-keep class com.baidu.ar.npc.** { *; }
-keep class com.baidu.lbsapi.** { *; }
-keep class com.baidu.location.** { *; }
-keep class com.baidu.mapapi.** { *; }
-keep class com.baidu.mapframework.open.aidl.** { *; }
-keep class com.baidu.mapsdkplatform.** { *; }
-keep class com.baidu.mapsdkvi.** { *; }
-keep class com.baidu.pano.platform.** { *; }
-keep class com.baidu.platform.** { *; }
-keep class mapsdkvi.com.gdi.bgl.** { *; }

#-libraryjars libs/bdplayer.jar
-keep class com.baidu.cloud.media.**{ *;}

# 播放内核混淆规则
-keep class com.baidu.cyberplayer.sdk.Keep
-keepattributes *Exceptions
-keep @com.baidu.cyberplayer.sdk.Keep class * {
public *;
}
-keepclasseswithmembers class * {
@com.baidu.cyberplayer.sdk.Keep <methods>;
}
-keepclasseswithmembers class * {
@com.baidu.cyberplayer.sdk.Keep <fields>;
}
-keepclasseswithmembers class * {
@com.baidu.cyberplayer.sdk.Keep <init>(...);
}
-keep class com.baidu.media.duplayer.Keep
-keep @com.baidu.media.duplayer.Keep class * {
public *;
}
-keep class com.baidu.vr.** {
*;
}
-keepclassmembers class * {
native <methods>;
}
-keepclasseswithmembers class * {
@com.baidu.media.duplayer.Keep <methods>;
}
-keepclasseswithmembers class * {
@com.baidu.media.duplayer.Keep <fields>;
}
-keepclasseswithmembers class * {
@com.baidu.media.duplayer.Keep <init>(...);
}

# keep FileProvider
-keep class android.support.v4.content.FileProvider*
-keepclassmembers class android.support.v4.content.FileProvider* { *; }

-keepclasseswithmembers,includedescriptorclasses class com.baidu.storage.swankv.** {
native <methods>;
long nativeHandle;
}

# bos 库混淆
-keep class * extends com.baidubce.model.AbstractBceResponse { public *; }
-keep class * extends com.baidubce.AbstractBceClient { public *; }
-keep class com.baidubce.AbstractBceClient { public *; }
-keep class com.baidubce.model.AbstractBceResponse { public *; }

9 宿主必须需要实现的能力接口

10 可以根据业务实现的接口

  • ISwanDeviceInfo : 传递OAID和androidid给到小程序框架
  • ISwanOpenAppConfig : 接管打开app相关能力
  • ISwanApkFetcher : 接管下载apk相关能力
  • DefaultSwanAppConfigImpl : 宿主可以继承此宿主配置默认实现,重写部分方法覆盖默认实现。(例如重写 needMoveHostTaskToFrontWhenBack方法,返回false即代表在小程序退出的时候不返回来源宿主页面,按照系统栈顺序返回,通过跨进程通信动态修改函数返回值,即可实现动态配置。)
  • ISailorSoDownloadAdapter : 宿主自定义百度T7浏览内核so后下载能力,具体见附录1

11 打开小程序的入口:SwanAppLaunchHelper.launch(scheme)

  • scheme为要打开的小程序的scheme协议.
  • 宿主的schemeHead://swan/appKey,appKey就是要打开小程序的唯一标识字符串,比如小程序中心的是”sc9Tq1iKawTnj5GhG6i77vzeIt4Crt5u”
    ,每个小程序的appkey可以从宿主平台查询,具体的可以参见小程序调启方式。
  • 查询链接 :https://ossunion.baidu.com/opensource/home/appmanagement.html

12 隐私政策地址

https://ossunion.baidu.com/opensourcedocs/introduction/principle/privacy/policy/

附1 So后下载说明

  1. 首先在依赖里,去除对deps.business.swan.webview.sailor_so与deps.business.swan.webview.so_lite的依赖,并添加deps.business.swan.webview.sailor的依赖。
  2. 实现一个so后下载的类,继承于“DefaultSailorSoDownloadAdapter”; 可参考demo工程实现: SailorSoDownloadImpl.java, 示例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Service
    @Singleton
    public class SailorSoDownloadImpl extends DefaultSailorSoDownloadAdapter {
    @Override
    public boolean isNeedDownload() {
    // so 后下载返回 true;直接依赖so则返回false
    return true;
    }
    }

  3. so后下载的时机是在第一次打开小程序的时候才进行,由于so的体积较大,会导致第一次打开的时间较长,如果希望在打开之前合适的时机主动触发预下载, 可以使用示例方法,如下:

    1
    2
    3
    // 1.此方法只可以在主进程中调用,子进程调用无效
    // 2.此方法线程安全,也是非阻塞调用,不耗时
    SailorSoDownloadConfig.downloadSoSilent()

附2 兼容配置说明

附2.1 兼容 gradle 6.0 以下版本

gradle 6.0 以下版本 的settings.gradle 文件不支持 pluginManagement{} 块,可以用以下方式代替:

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
// gradle 6.0 以下版本不支持 pluginManagement{},需注释掉 pluginManagement{} 和 plugins{}, 采用下方 buildscript{} 和 apply plugin 的方式集成。
//
// pluginManagement {
// repositories {
// // 1. 添加 Nest 插件所在的线上的仓库地址
// maven { url "https://repository.smartapps.cn/repository/swan-mvn-nest-public" }
// }
// plugins {
// // 2. 声明 Nest 插件及接入小程序框架的版本号,后续升级小程序框架,直接更新该版本号即可
// id("com.baidu.swan.nest") version "2.91.0.100"
// }
// }
// plugins {
// // 3. 声明 Nest 插件 id,应用小程序接入插件 nest,使宿主工程能引用小程序组件,或者编译小程序源码
// id("com.baidu.swan.nest")
// }

// gradle 6.0 以下版本采用下方 buildscript{} 和 apply plugin 的方式集成。
buildscript {
repositories {
// 1. 添加 Nest 插件所在的线上的仓库地址
maven { url 'https://repository.smartapps.cn/repository/swan-mvn-nest-public' }
mavenCentral()
google()
}
dependencies {
// 2. 声明 Nest 插件及接入小程序框架的版本号,后续升级小程序框架,直接更新该版本号即可
classpath "com.baidu.swan:nest:2.91.0.100"
}
}


// 3. 声明 Nest 插件 id,应用小程序接入插件 nest,使宿主工程能引用小程序组件,或者编译小程序源码
apply plugin: 'com.baidu.swan.nest'

// 下面可以正常声明宿主工程的其他模块
include ':app'

附3 注意事项说明:

  1. 宿主接入示例:参考lib-swan-demo-openhost
  2. 建议在进入小程序之前申请获取imei的权限,广告相关业务需要获取,否则可能会造成小程序广告统计不准
  3. SDK中一部分代码采用Kotlin编写,所以需要工程引入Kotlin环境。
  4. android Q版本以后对于应用访问权限进一步收紧,访问图片相册等路径需要在manifest文件添加android:requestLegacyExternalStorage="true"
  5. android R版本以后收紧应用列表访问权限,若宿主配置的targetSdkVersion>=30,则在android R版本将无法访问已安装应用列表。
    建议在manifest声明”android.permission.QUERY_ALL_PACKAGES”权限,以保证小程序及广告业务可正常查询与跳转到外部应用。