新增插件模块管理

This commit is contained in:
2023-06-14 13:41:12 +08:00
parent 29ddc54303
commit 3f9e95ce7d
30 changed files with 703 additions and 17 deletions

View File

@@ -92,6 +92,11 @@ android {
exclude 'lib/armeabi-v7a/libmmlic.so'
exclude 'lib/armeabi-v7a/libMNN_CL.so'
exclude 'lib/armeabi-v7a/libMNN_Express.so'
//美颜
exclude 'lib/armeabi-v7a/libCNamaSDK.so'
exclude 'lib/arm64-v8a/libCNamaSDK.so'
exclude 'lib/armeabi-v7a/libfuai.so'
exclude 'lib/arm64-v8a/libfuai.so'
}
compileOptions {
@@ -138,7 +143,10 @@ android {
'Resources/*',
'Asset/*',
'image_effect_shaders/*',
'internal/*'
'internal/*',
//美颜基础组件
'model/ai_face_processor_lite.bundle',
'graphics/face_beautification.bundle'
]))
}
}
@@ -200,9 +208,9 @@ android {
signingConfig signingConfigs.release
}
debug {
minifyEnabled true
shrinkResources true
zipAlignEnabled true
minifyEnabled false
shrinkResources false
zipAlignEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}

View File

@@ -11,9 +11,9 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
import android.os.Process;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -26,6 +26,7 @@ import com.google.firebase.FirebaseApp;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.google.firebase.crashlytics.FirebaseCrashlytics;
import com.shayu.phonelive.utils.LogUtils;
import com.shayu.phonelive.utils.PluginManager;
import com.tencent.imsdk.v2.V2TIMGroupMemberInfo;
import com.tencent.imsdk.v2.V2TIMManager;
import com.tencent.imsdk.v2.V2TIMSimpleMsgListener;
@@ -248,6 +249,7 @@ public class AppContext extends CommonAppContext {
configSPApp();
//初始化美颜SDK
// FaceManager.initFaceUnity(this);
PluginManager.getInstance().loadAnchorPlugin();
}
/**
@@ -289,7 +291,7 @@ public class AppContext extends CommonAppContext {
.setMainCrashHandler((t, e) -> {
Log.e("ApplicationError", "主线程异常");//此处log只是展示当debug为true时主类内部log会打印异常信息
e.printStackTrace();
AppManager.runDebugCode(()->{
AppManager.runDebugCode(() -> {
//闪退后finish所有Activity并且杀死进程
for (WeakReference<Activity> activity : activities) {
if (activity != null && activity.get() != null) {

View File

@@ -0,0 +1,221 @@
package com.shayu.phonelive.utils;
import static com.yunbao.faceunity.utils.FURenderer.BUNDLE_AI_FACE;
import static com.yunbao.faceunity.utils.FaceUnityConfig.BUNDLE_FACE_BEAUTIFICATION;
import android.content.Context;
import android.os.Build;
import android.util.Log;
import com.yunbao.common.CommonAppContext;
import com.yunbao.common.utils.DownloadUtil;
import com.yunbao.common.utils.StringUtil;
import com.yunbao.faceunity.utils.FileUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import dalvik.system.BaseDexClassLoader;
import dalvik.system.DexClassLoader;
import dalvik.system.PathClassLoader;
/**
* 插件加载器
*/
public class PluginManager {
private static PluginManager manager;
private static final String TAG = "插件管理器";
private String anchorPluginDownloadUrl = "http://192.168.137.1:12345/shares/ce47aa99-3e73-4a79-8a2f-e17a2d527953";
private PluginManager() {
}
public static PluginManager getInstance() {
if (manager == null) {
manager = new PluginManager();
}
return manager;
}
/**
* 设置主播插件下载地址
*/
public void setAnchorPluginDownloadUrl(String anchorPluginDownloadUrl) {
this.anchorPluginDownloadUrl = anchorPluginDownloadUrl;
}
/**
* 加载主播插件
*/
public void loadAnchorPlugin() {
new Thread(() -> {
try {
if (Arrays.asList(CommonAppContext.sInstance.getAssets().list("")).contains("anchorPlugin.apk")) {
FileUtils.copyAssetsFile(CommonAppContext.sInstance,"anchorPlugin.apk","anchorPlugin.apk",CommonAppContext.sInstance.getFilesDir().getAbsolutePath() + File.separator + "plugin_download");
}
Log.d(TAG,"解压assets下的文件");
} catch (IOException e) {
e.printStackTrace();
}
File sdk = new File(CommonAppContext.sInstance.getFilesDir().getAbsolutePath() + File.separator + "plugin_download" + File.separator + "anchorPlugin.apk");
if (!sdk.exists()) {
if (StringUtil.isEmpty(anchorPluginDownloadUrl)) {
Log.e(TAG, "主播下载地址为空");
return;
}
downloadAnchorSdk();
return;
}
String outDir = CommonAppContext.sInstance.getFilesDir().getAbsolutePath() + File.separator + "plugin";
loadFaceSo(sdk, outDir);
loadFaceBundle(sdk, outDir);
getAnchorPluginVersion();
}).start();
}
/**
* 加载美颜so文件
*
* @param plugin 插件apk文件
* @param outDir 解压路径
*/
private void loadFaceSo(File plugin, String outDir) {
unzip(plugin.getAbsolutePath(), outDir, ".so");
String[] abis = Build.SUPPORTED_ABIS;
String abi = Arrays.asList(abis).contains("arm64-v8a") ? "arm64-v8a" : "armeabi-v7a";
File plugins = new File(outDir + File.separator + "lib" + File.separator + abi);
loadSo(plugins, "libfuai");
loadSo(plugins, "libCNamaSDK");
}
/**
* 设置美颜Bundle文件
*
* @param plugin 插件apk文件
* @param outDir 解压路径
*/
private void loadFaceBundle(File plugin, String outDir) {
unzip(plugin.getAbsolutePath(), outDir, ".bundle");
BUNDLE_AI_FACE = outDir + File.separator + "assets" + File.separator + BUNDLE_AI_FACE;
BUNDLE_FACE_BEAUTIFICATION = outDir + File.separator + "assets" + File.separator + BUNDLE_FACE_BEAUTIFICATION;
}
/**
* 加载指定so
*
* @param dir so文件路径
* @param file so文件名字
*/
private void loadSo(File dir, String file) {
file += ".so";
if (new File(dir.getAbsolutePath() + File.separator + file).exists()) {
System.load(dir + File.separator + file);
Log.d(TAG, "加载成功 "+dir + File.separator + file );
} else {
Log.e(TAG, "不存在 "+dir + File.separator + file );
}
}
/**
* 下载主播插件包
*/
private void downloadAnchorSdk() {
String downloadDir = new File(CommonAppContext.sInstance.getFilesDir().getAbsolutePath() + File.separator + "plugin_download").getAbsolutePath();
new DownloadUtil().download("plugin", downloadDir, "anchorPlugin.apk", anchorPluginDownloadUrl, new DownloadUtil.Callback() {
@Override
public void onSuccess(File file) {
Log.d(TAG, "下载成功 "+file );
loadAnchorPlugin();
}
@Override
public void onProgress(int progress) {
}
@Override
public void onError(Throwable e) {
}
});
}
public String getAnchorPluginVersion() {
try {
File sdk = new File(CommonAppContext.sInstance.getFilesDir().getAbsolutePath() + File.separator + "plugin_download" + File.separator + "anchorPlugin.apk");
DexClassLoader loader = new DexClassLoader(
sdk.getAbsolutePath(),
sdk.getParent(),
sdk.getParent(),
Context.class.getClassLoader());
Object version = loader.loadClass("com.pdlive.pluginsForAnchor.MainPlugin").getMethod("getVersion").invoke(null);
Log.i(TAG, "主播插件版本号:" + version);
return (String) version;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 解压zip文件
*
* @param zip zip文件
* @param outDir 解压路径
* @param suffix 过滤
*/
private boolean unzip(String zip, String outDir, String suffix) {
FileOutputStream out;
byte buffer[] = new byte[1024];
try {
ZipInputStream zis = new ZipInputStream(new FileInputStream(zip));
ZipEntry entry = zis.getNextEntry();
while (entry != null) {
String name = entry.getName();
if (entry.isDirectory()) {
File newDir = new File(outDir + entry.getName());
newDir.mkdir();
} else if (name.endsWith(suffix)) {
File outputFile = new File(outDir + File.separator + name);
String outputPath = outputFile.getCanonicalPath();
name = outputPath
.substring(outputPath.lastIndexOf("/") + 1);
outputPath = outputPath.substring(0, outputPath
.lastIndexOf("/"));
File outputDir = new File(outputPath);
outputDir.mkdirs();
outputFile = new File(outputPath, name);
outputFile.createNewFile();
out = new FileOutputStream(outputFile);
int tmp = 0;
while ((tmp = zis.read(buffer)) > 0) {
out.write(buffer, 0, tmp);
}
/* do {
tmp = zis.read(buffer);
if (tmp <= 0) {
break;
} else {
out.write(buffer, 0, tmp);
}
} while (true);*/
out.close();
}
entry = zis.getNextEntry();
}
zis.close();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}