一、简介
安卓开发中使用Android studio集成三方SDK(比如腾讯视频云移动直播、播放器、短视频、实时音视频),通常有两种集成方式:aar集成、jar so集成。安卓集成已经很成熟了,详见SDK集成指引。
二、动态加载so
随着项目业务越来越多,对APK 体积大小要求尽可能的瘦身,通常可以考虑采用在线加载的方式减少最终 apk 安装包的大小。
以移动直播5.4全功能专业版(LiteAVSDK_Professional_Android_5.4.6097)为例,整个 SDK 的体积主要来自于 so 文件,这些 so 文件是 SDK 正常运行所依赖的音视频编解码库、图像处理库 以及 声学处理组件。各个 so 库的具体作用,可以阅读 库说明。
具体改造如下:
- 使用 jar so 方式集成,到官网下载 SDK,解压 LiteAVSDK_xxx.zip 压缩包后得到 libs 目录,里面主要包含 so 文件和 jar 文件。
- 上传 SO 文件 将 SDK 压缩包中的 so 文件上传到 CDN,并记录下载地址,比如 http://xxx.com/so_files.zip。
- 启动准备 在用户启动 SDK 相关功能前,比如开始播放视频之前,先用 loading 动画提示用户“正在加载相关的功能模块”。
- 下载 SO 文件 在用户等待过程中,APP 就可以到 http://xxx.com/so_files.zip 下载 so 文件,并存入应用目录下(比如应用根目录下的 files 文件夹),为了确保这个过程不受运营商 DNS 拦截的影响,请在文件下载完成后校验 so 文件的完整性。
- 加载 SO 文件 等待所有 so 文件就位以后,调用 TXLiveBase 的 setLibraryPath 将下载的目标 path 设置给 SDK, 然后再调用 SDK 的相关功能。之后,SDK 会到这些路径下加载需要的 so 文件并启动相关功能。
二、示例demo
1、工具类的写法。
下载、解压、校验完整性的过程,由客户自己灵活完成,demo就不给出演示了。我们直接从复制到内部存储开始
代码语言:javascript复制//FileUtils类
public static boolean copyFolder (String oldPath , String newPath){
File newFile = new File(newPath);
if(!newFile.exists()){
if(!newFile.mkdirs()){
Log.e("TAG","无法创建路径");
return false;
}
}
File oldFile = new File(oldPath);
String[] files = oldFile.list();
Log.i("TAG", "files.length: " files.length);
File temp;
for(String file : files){
if(oldPath.endsWith(File.separator)){
temp = new File(oldFile file);
}else{
temp = new File(oldPath File.separator file);
}
if(temp.isDirectory()){
copyFolder(oldPath "/" file , newPath "/" file);
}else if(!temp.exists()){
Log.e("TAG", "copyFolder: oldFile not exist");
return false;
}else if(!temp.isFile()){
Log.e("TAG", "copyFolder: oldFile not file");
return false;
}else if(!temp.canRead()){
Log.e("TAG", "copyFolder: oldFile cannot read");
return false;
}else{
try {
FileInputStream fileInputStream = new FileInputStream(temp);
FileOutputStream fileOutputStream = new FileOutputStream(newPath "/" temp.getName());
byte[] buffer = new byte[1024];
int byteRead;
while ((byteRead = fileInputStream.read(buffer))!=-1){
fileOutputStream.write(buffer,0,byteRead);
}
fileInputStream.close();
fileOutputStream.flush();
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
File fileile = new File(newPath "/" temp.getName());
fileile.setWritable(true);
fileile.setReadable(true);
fileile.setExecutable(true);
}
}
return true ;
}
2、调用setLibraryPath开始动态加载so
代码语言:javascript复制//下载so的外部存储目录,比如sd卡下的armeabi文件夹
oldFilePath = Environment.getExternalStorageDirectory().getPath() "/armeabi";
//应用的根目录file文件下新建armeabi文件夹
newFilePath = getFilesDir().getAbsolutePath() "/armeabi";
//复制到内存存储
FileUtils.copyFolder(oldFilePath, newFilePath)
//sdk接口动态加载so
TXLiveBase.setLibraryPath(newFilePath);
3、验证
代码语言:javascript复制//设置在 Android Studio 的控制台打印 SDK 的相关输出。
TXLiveBase.setConsoleEnabled(true);
//获取sdk版本号
String sdkVersionStr = TXLiveBase.getSDKVersionStr();
Log.i("TAG", "sdkVersionStr: " sdkVersionStr);
//开始推流
mLivePusher.startPusher(rtmpUrl.trim());
正常情况下可以推流成功,如上图。踩到坑的话会遇到如下crash,请重新检查集成配置。
至此算是全部完成了。
三、商业版动态加载so
商用企业版相较于专业版,增加了大眼、瘦脸、动效贴纸、绿幕等特效功能,是基于优图实验室的人脸识别技术和天天P图的美妆技术为基础开发的特权功能,腾讯云小直播团队通过跟优图和P图团队合作,将这些特效深度整合到 LiteAVSDK 的图像处理流程中,以实现更好的视频特效。
如果是集成的商业版SDK,比如移动直播5.4商业版(LiteAVSDK_Enterprise_Android_5.4.6097),解压sdk包,会发现多了一些jar、so库,而这些so库的动态加载方式,优图实验室有如下特殊加载要求(6.8商业版已经优化了这里,祥见《LiteAVSDK商业版6.6 ,安卓集成动态加载so》)。
1、这三个so库必需要在本地加载。
2、这些so库需要按照如下顺序动态加载。
代码语言:javascript复制//sdk接口动态加载so
TXLiveBase.setLibraryPath(newFilePath);
//系统接口动态加载so
loadLibrary(newFilePath, "YTCommon");
loadLibrary(newFilePath, "image_filter_common");
loadLibrary(newFilePath, "image_filter_gpu");
loadLibrary(newFilePath, "algo_rithm_jni");
loadLibrary(newFilePath, "format_convert");
loadLibrary(newFilePath, "ParticleSystem");
loadLibrary(newFilePath,"nnpack");
loadLibrary(newFilePath, "YTHandDetector");
loadLibrary(newFilePath, "GestureDetectJni");
loadLibrary(newFilePath,"YTIllumination");
loadLibrary(newFilePath,"YTFaceTrackPro");
loadLibrary(newFilePath,"algo_youtu_jni");
private static boolean loadLibrary(String path, String name) {
boolean loadSucess = false;
try {
if (!TextUtils.isEmpty(path)) {
String libName = path "/lib" name ".so";
File file = new File(libName);
if (file.exists()) {
Log.i("TAG", libName " exist, " file.length());
}
else {
Log.i("TAG", libName " not exist");
}
file.setExecutable(true);
file.setReadable(true);
file.setWritable(true);
System.load(libName);
loadSucess = true;
}
} catch (Error e1) {
Log.i("NativeLoad","load library : " e1.toString());
} catch (Exception e) {
Log.i("NativeLoad","load library : " e.toString());
}
return loadSucess;
}
3、验证动效功能
代码语言:javascript复制//设置动效Licence
TXLiveBase.getInstance().setLicence(context, LicenceUrl, Key);
//验证Licence
TXLiveBase.getInstance().getLicenceInfo(context);
//设置推流动效
mLivePusher.setMotionTmpl(params.mMotionTmplPath);
正常情况下可以打开动效,如上图。踩到坑的话会遇到如下crash,请重新检查集成配置。
四、相关知识
1、目前几种 Android CPU ABI
CPU 架构 | 描述 |
---|---|
armeabi | 第5代 ARM v5TE,使用软件浮点运算,兼容所有ARM设备,通用性强,速度慢 |
armeabi-v7a | 第7代 ARM v7,使用硬件浮点运算,具有高级扩展功能 |
arm64-v8a | 第8代,64位,包含AArch32、AArch64两个执行状态对应32、64bit |
x86 | intel 32位,一般用于平板 |
x86_64 | intel 64位,一般用于平板 |
mips | 少接触 |
mips64 | 少接触 |
2、设置 APK 的对应支持
代码语言:javascript复制//非商业版,6.3之前的版本支持armeabi、armeabi-v7a,6.3开始支持armeabi、armeabi-v7a、arm64-v8a
//商业版,只支持armeabi
defaultConfig {
ndk {
abiFilters "armeabi"//,"armeabi-v7a","arm64-v8a","x86_64"
}
}
3、查看 手机CPU ABI
4、Zygote相关知识
- 所有的App在运行时,都是由Zygote进程创建VM再运行的。
- 一般设备只支持32位系统,但现在的新设备都已经支持64位(同时兼容32位)。对于这些新设备来说,有两个Zytgote(一个32位,一个64位)进程同时运行。
所以当App运行在64位系统上,又区分以下三种情况:
- 如果App只包含64位的so库,则它将运行在一个64位的进程中,即VM是由Zytgote 64创建的。
- 如果App包含32位的so库,则它将运行在一个32位的进程中,即VM是由Zytgote创建的。
- 如果App不包含任何so库,则它将默认运行在64位的进程中。
所以当你的工程只指定支持armeabi,而运行在64位手机上动态加载so,会出现闪退。解决办法就是:先把一个32位的so文件打进安装包,其它so库在运行时动态加载,这样App启动的是32位进程,动态加载的so库也是32位版本,运行时就不再闪退。
五、资源
相关文章:
LiteAVSDK商业版6.6 ,安卓集成动态加载so
动态加载so库的实现方法与问题处理
Android 的 so 文件加载机制提问源码总结参考资料
demo下载