插件化实现二 加载未安装apk

tech2023-11-25  87

加载未安装apk实现插件化

通过加载未安装应用的方式实现app插件化获取未安装应用的信息获取未安装应用的Resources对象获取插件应用中的图片简单使用

通过加载未安装应用的方式实现app插件化

学习应用插件化技术,通过加载未安装apk,实现插件化功能,此处做个笔记,方便查阅

获取未安装应用的信息

/** * @param apkDir 未安装应用的路径,包含应用带apk后缀的名称 * @return 获得未安装应用的信息 * */ private String[] getUninstallApkInfo(Context context,String apkDir)throws Exception{ String[] apkInfo = new String[2]; PackageManager pm = context.getPackageManager(); PackageInfo packageInfo = pm.getPackageArchiveInfo(apkDir, PackageManager.GET_ACTIVITIES); if(packageInfo!=null){ ApplicationInfo appInfo = packageInfo.applicationInfo; String versionName = packageInfo.versionName; String packageName = appInfo.packageName; Drawable icon = pm.getApplicationIcon(appInfo); String appName = pm.getApplicationLabel(appInfo).toString();//此处获取到的appName与应用包名一样 apkInfo[0] = "plug.apk"; //插件apk名称 apkInfo[1] = packageName; //插件apk包名 } return apkInfo; }

获取未安装应用的Resources对象

/** * 反射获取插件apk的Resources对象 * @para apkDir 插件应用路径,带有.apk的名称后辍 * @return 得到对应插件应用的Resource对象 * */ private Resources getPluginResources(Context context,String apkDir) { try { AssetManager assetManager = AssetManager.class.newInstance(); Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class); //将未安装的apk添加进AssetManager中,第二个参数是插件apk的路径带apk名 addAssetPath.invoke(assetManager, apkDir); Resources superRes = context.getResources(); Resources resources = new Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration()); return resources; }catch (Exception e){ e.printStackTrace(); return null; } }

获取插件应用中的图片

/** * 获取资源文件 * */ public Drawable dynamicLoadApk() throws Exception{ String apkName = "plugin.apk"; //名称随意,记住就行 String mApkDir = Environment.getExternalStorageDirectory().getPath()+File.separator+"Pictures"+File.separator+apkName; String apkPackageName = mApkInfo[1]; //在应用安装目录下创建一个名为app_dex文件夹目录,如果已经存在则不创建 File optimizedDirFile = mContext.getDir("dex", Context.MODE_PRIVATE); // 参数一:包含dex的apk或jar路径 // 参数二:apk,jar解压生成dex文件的存储路径 // 参数三:本地library库目录,一般为null // 参数四:父classLoader DexClassLoader dexClassLoader = new DexClassLoader(mApkDir, optimizedDirFile.getPath(), null, ClassLoader.getSystemClassLoader()); //使用apk自己的类加载器,加载图片资源类,其它资源文件类似,修改.R$mipmap中的mipmap为string可获取字符串class对象,,mApkInfo[1]是插件apk的包名 Class<?> clazz = dexClassLoader.loadClass(Class<?> clazz = dexClassLoader.loadClass(apkPackageName + ".R$mipmap"); + ".R$mipmap"); //获取名称为one的图片资源*********************** Field field = clazz.getDeclaredField("one"); int resId = field.getInt(R.mipmap.class); //得到插件apk的resources Resources resources = getPluginResources(mContext, mApkDir); if(resources!=null){ Drawable drawable = resources.getDrawable(resId); return drawable; } return null; }

简单使用

public class MainActivity extends Activity { private static final String appName = "plug.apk"; private Drawable drawable; Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 1: bg.setImageDrawable(drawable); break; } } }; private ImageView bg; private LoadUtils loadUtils; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } private void init() { bg = ((ImageView) findViewById(R.id.bg)); try { loadUtils = new LoadUtils(this, appName); drawable = loadUtils.dynamicLoadApk(); } catch (Exception e) { e.printStackTrace(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu,menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.update: mHandler.sendEmptyMessage(1); break; } return true; } }
最新回复(0)