android 中的動態加載
阿新 • • 發佈:2018-09-16
print mpat tag loader setfile 日誌 pro bool 就會 這裏所說的動態加載是加載一個包(插件),其實就是一個 apk只是這個apk 動態加載而已。
創建一個要動態加載的 apk(插件)
寫一個類用於動態加載
//DynamicTest.java
創建一個要動態加載的 apk(插件)
寫一個類用於動態加載
//DynamicTest.java
package com.example.liuhailong.idynamic; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; public class DynamicTest { public void showPluginWindow(Context context) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setMessage("我是插件的對話框"); builder.setTitle(R.string.app_name); builder.setNegativeButton("取消", new Dialog.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); Dialog dialog = builder.create(); dialog.show(); } }
其時就是一個工程可以運行
再創建一個工程
把剛才編譯的 apk 放到 assets 目錄下
assets創建:
先搞清動態加載其實就是把 apk 加載到內存所以有讀apk,寫入的操作
定義一個讀 apk 的類,把 apk 寫入sdcard的文件
//Utils.java
package com.example.liuhailong.testplugin; import android.content.Context; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Utils { private static final int BUF_SIZE = 2048; /** * 將插件資源從assets寫入到sdcard上 * @param context 上下文 * @param assetFile asset目錄下的文件名稱 * @param sdCardPath 要寫入到sdcard的文件 */ public static boolean prepareDex(Context context, String assetFile, File sdCardPath) { BufferedInputStream bis = null; OutputStream dexWriter = null; try { bis = new BufferedInputStream(context.getAssets().open(assetFile)); dexWriter = new BufferedOutputStream(new FileOutputStream(sdCardPath)); byte[] buf = new byte[BUF_SIZE]; int len; while ((len = bis.read(buf, 0, BUF_SIZE))>0) { dexWriter.write(buf, 0, len); } dexWriter.close(); bis.close(); return true; } catch (IOException e) { e.printStackTrace(); } return false; } }
再寫主函數動態加載
package com.example.liuhailong.testplugin; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.content.Context; import android.os.Bundle; import android.view.View; import java.io.File; import java.lang.reflect.Method; import dalvik.system.DexClassLoader; public class MainActivity extends AppCompatActivity { private static String TAG = "MainActivity"; //apk文件存放的路徑 private String dexFilePath; //解壓出dex存儲路徑 private File dexFile; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.e(TAG, "當前的classloader:" + getClassLoader()); Log.e(TAG, "系統的classloader:" + ClassLoader.getSystemClassLoader()); //設置dexFilePath dexFilePath = getExternalFilesDir(null).getPath() + File.separator + "plugin.apk"; System.out.println("dexFilePath:" + dexFilePath); dexFile = getDir("dex", 0); boolean success = Utils.prepareDex(this, "PluginDemo.apk", new File(dexFilePath)); if (!success) return; //創建DexClassLoader final DexClassLoader dexClassLoader = new DexClassLoader(dexFilePath, dexFile.getAbsolutePath(), null, getClassLoader()); findViewById(R.id.open_plug_button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { Class mClass = dexClassLoader.loadClass("com.example.liuhailong.idynamic.DynamicTest"); Log.e(TAG,"mClass的默認classLoader:"+mClass.getClassLoader()); Object dynamicTest = mClass.newInstance(); Method mMethod = mClass.getDeclaredMethod("showPluginWindow", new Class<?>[]{Context.class}); mMethod.setAccessible(true); mMethod.invoke(dynamicTest, MainActivity.this); } catch (Exception e) { e.printStackTrace(); } } }); } }
運行:
點擊就會自動加載:
日誌:
android 中的動態加載