編輯:關於Android編程
Android大型項目中為了減小apk的體積,可以采用插件化的方法,即一些不常用的功能獨立成插件,當用戶需要的使用的時候再從服務器上下載回來,動態加載。這樣就避免了為了滿足所有用戶需求而把功能全部打包到apk,導致apk體積的膨脹。所謂的插件,其實也是一個apk,但是一般都依賴正式對外發布的app,也叫宿主。本篇不討論插件化的原理和實現難點,只介紹怎麼使用以及優缺點。
Android插件化常用實現方案有兩種:
(1) DynamicLoadApk
(2) DroidPlugin
這兩個是目前比較主流的Android插件化實現方案,在Github的星星數很高,兩者的Github地址如下:
DynamicLoadApk的Github地址:https://github.com/singwhatiwanna/dynamic-load-apk
DroidPlugin的Github地址:https://github.com/Qihoo360/DroidPlugin
(1) DynamicLoadApk是由團隊維護的,但是目前已經很長時間沒有更新了,途牛用的就是這個插件化框架
優點:
缺點:
插件apk必須實現DLBasePluginActivity,屬於侵入式的,以及不支持service 宿主調用插件和插件內部的相互調用都要使用DL提供的方法,而不能使用Android原生的api,例如:啟動Activity 插件開發有一套規定,因此造成插件開發門檻高,學習成本高(2) DroidPlugin是360公司開源的一個框架,已經在360手機助手上使用
優點:
缺點:
插件啟動速度太慢,而且宿主只能調用插件的LaunchMode的Activity,不能調用其他Activity(1) 導入Dynamic-load-apk中的lib。
下載Dynamic-load-apk後解壓,在Android Studio中新建工程DLTest(自己命名) –> new –> import module –>選擇lib所在的目錄:dynamic-load-apk-master\DynamicLoadApk\lib
(2) 新建插件模塊plugin,宿主模塊hZ喎?/kf/ware/vc/" target="_blank" class="keylink">vc3SjrNXiwb249sSjv+m2vMrHYXBwbGljYXRpb24sINfuuvO2vNKqyfqzyWFwa7XEoaPP7sS/xL/CvMjnz8I6PC9wPg0KPHA+PGltZyBhbHQ9"這裡寫圖片描述" src="/uploadfile/Collfiles/20160405/2016040509211921.png" title="\" />
編譯lib模塊,命令是build菜單–>make module lib,目的是為了獲得生成的jar文件,jar文件所在位置是lib\build\intermediates\bundles\debug\class.jar,復制jar文件重命名為lib.jar
(3) 導入lib.jar到plugin項目的libs目錄下,開發plugin項目,注意Activity要繼承DLBasePluginActivity ,R.layout.activity_test上就一個TextView,顯示”這個界面來自Plugin”
插件項目Plugin的MainActivity:
public class MainActivity extends DLBasePluginActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
}
}
注意:plugin模塊的buidle.gradle需要修改為如下:
dependencies {
provided fileTree(dir: 'libs', include: ['*.jar'])
.........
}
provided 意思是編譯時候使用,但不打包到APK中,這樣做是因為我們的宿主項目host中已經包含了lib.jar,如果插件中也包含的話就會報找不到plugin中的Activity的錯,原因是兩個包重復,必須要用host中的DL框架來加載plugin,而不是plugin自帶的DL框架
(4) 導入lib.jar到host項目的libs目錄下,開發host項目
host項目的MainActivity:
public class MainActivity extends Activity {
private Button btnTest;
private TextView tvTip;
@Override
protected 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);
//添加監聽器
this.btnTest.setOnClickListener(new View.OnClickListener() {
@Override
public 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));
}
//插件Bean
public static class PluginItem {
public PackageInfo packageInfo;
public String pluginPath;
public String launcherActivityName;
public String launcherServiceName;
public PluginItem() {
}
}
}
host的activity_main.xml:
注意:Host的AndroidManifest.xml中需要額外的聲明幾個DL框架中的類,否則運行時候找不到Activity.
Host的AndroidManifest.xml:
(5) 編譯plugin項目,將生成的plugin-debug.apk文件放入/mnt/sdcard/DynaminLoadHost目錄下,然後運行Host,運行結果如下:
Host可以,但plugin不可以。宿主項目可以依賴於lib項目,但是plugin必須使用jar文件,原因參見下面第3條
修改host文件的build.gradle文件
dependencies {
compile project(':lib')
.....
}
修改lib的build.gradle文件,不修改的話就會和host項目中的support-v4包沖突
dependencies {
provided fileTree(dir: 'libs', include: ['*.jar'])
}
Plugin不能將lib模塊打包到apk中,所以不能使用compile,只能使用provided,所以如果不用jar則plugin模塊的build.gradle只能如下:
dependencies {
provided project(':lib')
.....
}
呵呵,可惜這樣是不行的,project只能使用compile ,不能使用provided ,百度了半天沒有解決這個問題,如果你有辦法歡迎留言
一、關系型數據庫SQLIte 每個應用程序都要使用數據,Android應用程序也不例外
前言 本章繼續完善播放相關播放器的核心功能,為後續擴展打好基礎。系列 1、Android 使用Vitamio打造自己的萬能播放器(1)——准備
先看下項目結構: http多線程斷點下載涉及到 數據庫,多線程和http請求等幾個模塊,東西不是很多,想弄清楚也不是很困難,接下來我和大家分享下我的做法。 一、先看Ma
相信大家在小的時候都玩過拼圖游戲,現如今,手機普及,能在手機上玩的游戲越來越多,於是乎,重溫小時候,編寫這個簡易拼圖游戲,而且也能進一步加深Android的一些基礎知識。