新增插件模块管理
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
221
app/src/main/java/com/shayu/phonelive/utils/PluginManager.java
Normal file
221
app/src/main/java/com/shayu/phonelive/utils/PluginManager.java
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user