簡介
DroidPlugin 是360手機助手在Android系統(tǒng)上實現(xiàn)的一種新的插件機制:它可以在無需安裝、修改的情況下運行APK文件,此機制對改進大型APP的架構(gòu),實現(xiàn)多團隊協(xié)作開發(fā)具有一定的好處?
詳情請查看DroidPlugin的github地址
背景
- 將項目中某個相對獨立的功能模塊分解出來
- 例如:語音搜索功能模塊獨立出來,這樣減少了項目中依賴包的數(shù)量,減少了項目中某些包的層層依賴關(guān)系,將語音搜索模塊獨立成一個單獨的apk
- 可以獨立開發(fā)語音搜索模塊
- 假設(shè)主項目為Host,依賴library為DroidPlugin,獨立出來的語音模塊生成為voice.apk
應(yīng)用
這里將獨立出來的語音搜索模塊打包成單獨的apk,放在項目的assets目錄下
項目中的設(shè)置步驟:
- 導(dǎo)入DroidPlugin相關(guān)的library
- 在自己的Application當(dāng)中添加如下代碼
@Override
public void onCreate() {
super.onCreate();PluginHelper.getInstance().applicationOnCreate(getBaseContext());
}
@Override
protected void attachBaseContext(Context base) {PluginHelper.getInstance().applicationAttachBaseContext(base);
super.attachBaseContext(base);
}
- 配置主應(yīng)用AndroidManifest.xml中相關(guān)的組件和權(quán)限?
這里需要注意DroidPlugin library中需要的權(quán)限以及組件要在主項目Host中聲明?
還有就是Host中的權(quán)限只能比voice的多,不能少,否則會有問題 - 讀取assets里面的voice.apk并復(fù)制到sd上或者其他的可讀取存儲位置,然后再使用DroidPlugin進行安裝,這里將需要用到的一些方法封裝在PluginUtils工具類中。
- 當(dāng)voice.apk通過插件式的形式安裝完成以后,我們就可以通過如下方式啟動voice.apk
PluginUtils.startActivity(SearchResultActivity.
this,
"com.storm.smart.voice");
- 在Application或者MainActivty中加載voice.apk
/*** 通過DroidPlugin插件安裝voice.apk* 從sd卡根目錄讀取*/private void droidPluginInstall() {BfExecutor.getInstance().execute(
new Runnable() {
@Overridepublic void run() {
if (PluginUtils.copyApkFromAssets(getApplicationContext(),
"voice.apk",Environment.getExternalStorageDirectory().getAbsolutePath() +
"/voice.apk")) {PluginUtils.installApk(getApplicationContext(),Environment.getExternalStorageDirectory().getAbsolutePath() +
"/voice.apk",
"com.storm.smart.voice");}}});}
/*** 通過DroidPlugin插件安裝voice.apk* 從data下讀取,需要權(quán)限(有可能手機沒有sd卡)*/private void droidPluginInstall() {BfExecutor.getInstance().execute(
new Runnable() {
@Overridepublic void run() {String path =
"/data/data/" + getApplicationContext().getPackageName() +
"/files" +
"/voice.apk";
try {String command =
"chmod " +
"666" +
" " + path;Runtime runtime = Runtime.getRuntime();runtime.exec(command);}
catch (IOException e) {e.printStackTrace();}
if (PluginUtils.copyApkFromAssets(getApplicationContext(),
"voice.apk", path)) {PluginUtils.installApk(getApplicationContext(), path,
"com.storm.smart.voice");}}});}
- 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
- 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
public class PluginUtils {public static void startActivity(Activity activity, String packageName){PackageManager pm = activity.getPackageManager();Intent intent = pm.getLaunchIntentForPackage(packageName);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);activity.startActivity(intent);}
/*** 刪除apk* @param activity* @param packageName*/public static void doUninstall( Activity activity, String packageName) {
if (!PluginManager.getInstance().isConnected()) {Toast.makeText(activity,
"服務(wù)未連接", Toast.LENGTH_SHORT).show();}
else {
try {PluginManager.getInstance().deletePackage(packageName,
0);Toast.makeText(activity,
"刪除完成", Toast.LENGTH_SHORT).show();}
catch (RemoteException e) {e.printStackTrace();}}}
/*** 應(yīng)該在線程中安裝,此方法僅供測試* @param activity* @param apkPath* @param packageName*/public static boolean installApk(Context context, String apkPath, String packageName) {
if (!PluginManager.getInstance().isConnected()) {
return false;}
try {
if (PluginManager.getInstance().getPackageInfo(packageName,
0) !=
null) {}
else {
int re = PluginManager.getInstance().installPackage(apkPath,
0);
if(re == PluginManager.INSTALL_FAILED_NO_REQUESTEDPERMISSION){}
else{
return true;}}}
catch (Exception e) {e.printStackTrace();}
return false;}
/**安裝提示* @param context* @param tips*/public static void installTips(Context context,String tips){Looper.prepare();Toast.makeText(context, tips, Toast.LENGTH_SHORT).show();Looper.loop();}
/** 將assets文件下的apk讀取到讀取到指定路徑* @param context* @param fileName* @param path* @return*/public static boolean copyApkFromAssets(Context context, String fileName, String path) {
boolean copyIsFinish =
false;
try { InputStream is = context.getAssets().open(fileName); File file =
new File(path); file.createNewFile(); FileOutputStream fos =
new FileOutputStream(file);
byte[] temp =
new byte[
1024];
int i =
0;
while ((i = is.read(temp)) >
0) { fos.write(temp,
0, i); } fos.close(); is.close(); copyIsFinish =
true; }
catch (IOException e) { e.printStackTrace(); }
return copyIsFinish; } }
- 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
- 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
總結(jié)
最終我們會發(fā)現(xiàn)在/data/data/【host packageName】下有一個Plugin文件夾,文件夾中有個【voice packageName】文件夾,里面有voice的相關(guān)數(shù)據(jù)?
這樣voice.apk就以插件的方式嵌入到我們的主應(yīng)用中了。
原文地址:?http://blog.csdn.net/s003603u/article/details/50750335
總結(jié)
以上是生活随笔為你收集整理的Android实战】DroidPlugin插件化应用分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。