日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

[Android 插件化(一)] DynamicLoadApk的用法

發(fā)布時間:2025/3/15 Android 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [Android 插件化(一)] DynamicLoadApk的用法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1 簡介

Android大型項目中為了減小apk的體積,可以采用插件化的方法,即一些不常用的功能獨立成插件,當用戶需要的使用的時候再從服務器上下載回來,動態(tài)加載。這樣就避免了為了滿足所有用戶需求而把功能全部打包到apk,導致apk體積的膨脹。所謂的插件,其實也是一個apk,但是一般都依賴正式對外發(fā)布的app,也叫宿主。本篇不討論插件化的原理和實現難點,只介紹怎么使用以及優(yōu)缺點。?
Android插件化常用實現方案有兩種:

(1) DynamicLoadApk?
(2) DroidPlugin

這兩個是目前比較主流的Android插件化實現方案,在Github的星星數很高,兩者的Github地址如下:

DynamicLoadApk的Github地址:https://github.com/singwhatiwanna/dynamic-load-apk?
DroidPlugin的Github地址:https://github.com/Qihoo360/DroidPlugin

2 特點

(1) DynamicLoadApk是由團隊維護的,但是目前已經很長時間沒有更新了,途牛用的就是這個插件化框架?
優(yōu)點:

  • 插件不依賴宿主,對宿主開發(fā)者透明,提供三種依賴方式
  • 宿主和插件可以頻繁交互,啟動時間短

缺點:

  • 插件apk必須實現DLBasePluginActivity,屬于侵入式的,以及不支持service
  • 宿主調用插件和插件內部的相互調用都要使用DL提供的方法,而不能使用Android原生的api,例如:啟動Activity
  • 插件開發(fā)有一套規(guī)定,因此造成插件開發(fā)門檻高,學習成本高

(2) DroidPlugin是360公司開源的一個框架,已經在360手機助手上使用?
優(yōu)點:

  • 宿主和插件完全隔離,插件不依賴宿主,可以獨立安裝運行
  • 低入侵設計,插件不需要繼承任何類
  • 插件apk和普通apk一樣的,所以插件開發(fā)沒有門檻
  • 有大公司維護,有360手機助手這樣的商用app在使用

缺點:

  • 插件啟動速度太慢,而且宿主只能調用插件的LaunchMode的Activity,不能調用其他Activity

3 使用方法

(1) 導入Dynamic-load-apk中的lib。?
下載Dynamic-load-apk后解壓,在Android Studio中新建工程DLTest(自己命名) –> new –> import module –>選擇lib所在的目錄:dynamic-load-apk-master\DynamicLoadApk\lib

(2) 新建插件模塊plugin,宿主模塊host,這兩個模塊都是application, 最后都要生成apk的。項目目錄如下:

編譯lib模塊,命令是build菜單–>make module lib,目的是為了獲得生成的jar文件,jar文件所在位置是lib\build\intermediates\bundles\debug\class.jar,復制jar文件重命名為lib.jar

(3) 導入lib.jar到plugin項目的libs目錄下,開發(fā)plugin項目,注意Activity要繼承DLBasePluginActivity ,R.layout.activity_test上就一個TextView,顯示”這個界面來自Plugin”?
插件項目Plugin的MainActivity:

public class MainActivity extends DLBasePluginActivity {@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_test);} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意:plugin模塊的buidle.gradle需要修改為如下:

dependencies {provided fileTree(dir: 'libs', include: ['*.jar'])......... }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

provided 意思是編譯時候使用,但不打包到APK中,這樣做是因為我們的宿主項目host中已經包含了lib.jar,如果插件中也包含的話就會報找不到plugin中的Activity的錯,原因是兩個包重復,必須要用host中的DL框架來加載plugin,而不是plugin自帶的DL框架

(4) 導入lib.jar到host項目的libs目錄下,開發(fā)host項目?
host項目的MainActivity:

public class MainActivity extends Activity {private Button btnTest;private TextView tvTip;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);this.btnTest = (Button) findViewById(R.id.btn_test);this.tvTip = (TextView) findViewById(R.id.tv_tip);this.init();}//初始化private void init() {//獲取插件String pluginFolder = "/mnt/sdcard/DynamicLoadHost";File file = new File(pluginFolder);File[] plugins = file.listFiles();//判斷有沒有插件if (plugins == null || plugins.length == 0) {this.tvTip.setVisibility(View.VISIBLE);return;}//調用第一個插件File plugin = plugins[0];final PluginItem item = new PluginItem();item.pluginPath = plugin.getAbsolutePath();item.packageInfo = DLUtils.getPackageInfo(this, item.pluginPath);//獲取插件的啟動Activity的名稱if (item.packageInfo.activities != null && item.packageInfo.activities.length > 0) {item.launcherActivityName = item.packageInfo.activities[0].name;}//獲取插件啟動Service的名稱if (item.packageInfo.services != null && item.packageInfo.services.length > 0) {item.launcherServiceName = item.packageInfo.services[0].name;}//顯示插件tvTip.setText("檢測到一個插件:" + item.pluginPath);//加載插件DLPluginManager.getInstance(this).loadApk(item.pluginPath);//添加監(jiān)聽器this.btnTest.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//提示Toast.makeText(getApplicationContext(), "開始調用插件", Toast.LENGTH_SHORT).show();//調用插件usePlugin(item);}});}//調用插件private void usePlugin(PluginItem pluginItem) {DLPluginManager pluginManager = DLPluginManager.getInstance(this);pluginManager.startPluginActivity(this, new DLIntent(pluginItem.packageInfo.packageName, pluginItem.launcherActivityName));}//插件Beanpublic static class PluginItem {public PackageInfo packageInfo;public String pluginPath;public String launcherActivityName;public String launcherServiceName;public PluginItem() {}} }
  • 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
  • 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

host的activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><TextView android:id="@+id/tv_tip"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:text="沒有檢測到插件"/><Button android:id="@+id/btn_test"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/tv_tip"android:layout_marginTop="10dp"android:text="測試調用插件"/></RelativeLayout>
  • 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
  • 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

注意:Host的AndroidManifest.xml中需要額外的聲明幾個DL框架中的類,否則運行時候找不到Activity.

Host的AndroidManifest.xml:

<manifest package="com.host"xmlns:android="http://schemas.android.com/apk/res/android"><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><application android:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"android:label="@string/app_name"android:theme="@style/AppTheme.NoActionBar"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity><activity android:name="com.ryg.dynamicload.DLProxyActivity"android:label="@string/app_name"><intent-filter><action android:name="com.ryg.dynamicload.proxy.activity.VIEW"/><category android:name="android.intent.category.DEFAULT"/></intent-filter></activity><activity android:name="com.ryg.dynamicload.DLProxyFragmentActivity"android:label="@string/app_name"><intent-filter><action android:name="com.ryg.dynamicload.proxy.fragmentactivity.VIEW"/><category android:name="android.intent.category.DEFAULT"/></intent-filter></activity><service android:name="com.ryg.dynamicload.DLProxyService"/></application></manifest>
  • 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
  • 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

(5) 編譯plugin項目,將生成的plugin-debug.apk文件放入/mnt/sdcard/DynaminLoadHost目錄下,然后運行Host,運行結果如下:?

4 總結

  • 1 宿主和插件沒有任何聯系,但是插件需要繼承DLBasePluginActivity,這個不太友好
  • 2 侵入式的,對插件apk的開發(fā)限制太多,例如:必須繼承DLBasePluginActivity,啟動時候必須調用startPluginActivity(new?
    DLIntent(getPackageName(),TestActivity.class))
  • 3 這個框架學習成本高,限制多,聯調不方便,不建議使用
  • 4 目前比較好的插件有360公司的DroidPlugin, 以及類似友盟的第三方解決方案ApkPlug

5 擴展

1 Android Studio中可以不用jar文件嗎?

Host可以,但plugin不可以。宿主項目可以依賴于lib項目,但是plugin必須使用jar文件,原因參見下面第3條

2 Host項目如何直接依賴lib項目,而不用jar文件?

修改host文件的build.gradle文件

dependencies {compile project(':lib')..... }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

修改lib的build.gradle文件,不修改的話就會和host項目中的support-v4包沖突

dependencies {provided fileTree(dir: 'libs', include: ['*.jar']) }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

3 為什么plugin必須使用jar文件?

Plugin不能將lib模塊打包到apk中,所以不能使用compile,只能使用provided,所以如果不用jar則plugin模塊的build.gradle只能如下:

dependencies {provided project(':lib')..... }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

呵呵,可惜這樣是不行的,project只能使用compile ,不能使用provided ,百度了半天沒有解決這個問題,如果你有辦法歡迎留言

6 參考博客:

(1)?http://blog.csdn.net/singwhatiwanna/article/details/40283117

7 轉載請注明來自“梧桐那時雨”的博客:http://blog.csdn.net/fuchaosz/article/details/51056947

總結

以上是生活随笔為你收集整理的[Android 插件化(一)] DynamicLoadApk的用法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。