動態加載就是用到的時候再去加載,也叫懶加載,也就意味着用不到的時候是不會去加載的。java
jar是JDK提供的,dx是Android SDK提供,只要配置好環境變量,可在任意位置執行
我是在debug中執行,方便使用
jar -cvf cn 生成jar包
dx --dex --output=target.jar source.jar 生成包含dex的jar包
注意:把dex放入assets後,把DynamicDex.java刪掉或更名,不然加載的是它,而不是dex中的類android
public class DexUtil { public static void loadDexClass(final Context context, final String dexName, final Handler handler) { new AsyncTask<Void, Void, String>() { @Override protected String doInBackground(Void... params) { File cacheFile = getCacheDir(context.getApplicationContext()); String internalPath = cacheFile.getAbsolutePath() + File.separator + dexName; Log.v("DexUtil", "internalPath = " + internalPath); File desFile = new File(internalPath); if (!desFile.exists()) { try { if (!desFile.exists()) { desFile.createNewFile(); copyFiles(context, dexName, desFile); } } catch (IOException e) { e.printStackTrace(); } } return internalPath; } @Override protected void onPostExecute(String internalPath) { super.onPostExecute(internalPath); File dexOutputDir = context.getDir("dex", 0); File soOutputDir = context.getDir("lib", 0); String librarySerachPath = soOutputDir.getAbsolutePath().replace("app_lib", "lib"); Log.v("DexUtil", "librarySerachPath = " + librarySerachPath); DexClassLoader dexClassLoader = new DexClassLoader(internalPath, dexOutputDir.getAbsolutePath(), librarySerachPath, context.getClassLoader());//ClassLoader.getSystemClassLoader().getParent()); Message msg = new Message(); msg.obj = dexClassLoader; handler.sendMessage(msg); } }.execute(); } public static void copyFiles(Context context, String fileName, File desFile) { InputStream in = null; OutputStream out = null; try { in = context.getApplicationContext().getAssets().open(fileName); out = new FileOutputStream(desFile.getAbsolutePath()); byte[] bytes = new byte[1024]; int i; while ((i = in.read(bytes)) != -1) { out.write(bytes, 0, i); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException e) { e.printStackTrace(); } } } public static boolean hasExternalStorage() { return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); } /** * 獲取緩存路徑 * * @param context * @return 返回緩存文件路徑 */ public static File getCacheDir(Context context) { File cache; if (hasExternalStorage()) { cache = context.getExternalCacheDir(); } else { cache = context.getCacheDir(); } if (!cache.exists()) cache.mkdirs(); return cache; } }
Dex加載步驟:
1)把assets中的dex的jar拷貝到met目錄下
文件拷貝須要添加權限緩存
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2)利用DexClassLoader加載Dex,把dex放入到相關目錄上
注意:文件的拷貝須要放在子線程中運行
3.利用反射加載app
public class MainActivity extends AppCompatActivity { public static DexClassLoader mapLoader; TextView tv_hello; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv_hello = (TextView) this.findViewById(R.id.tv_hello); DexUtil.loadDexClass(this, "dex_dynamic.jar", dexHandler); } private Handler dexHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); mapLoader = (DexClassLoader) msg.obj; try { Class DynamicDex_Class = mapLoader.loadClass("cn.liufei.dynamicdex.DynamicDex"); Constructor DynamicDex_Cons = DynamicDex_Class.getConstructor(null); Object DynamicDex_Obj = DynamicDex_Cons.newInstance(); Method test_meth = DynamicDex_Class.getMethod("test", null); String result = (String) test_meth.invoke(DynamicDex_Obj, null); tv_hello.setText(result); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }; }
Demo地址:連接: https://pan.baidu.com/s/1kVMQ6jX 密碼: i4vpide