android 嵌套 apk 从一个apk启动另外一个apk
a.apk-主应用 b.apk-被启动应用
主要思想:把b.apk放到assets目录下,由于有大小限制(1M),所以改名成b.mp3(因为mp3,jpg,png,mp4等不会检查,不会限制大小),然后在用的时候再改回来
1.具体实现:
public void intallApp(Context context) {
try {
String path = context.getFilesDir().getAbsolutePath()+ "/b.apk"; //从assets中解压到这个目录
File f = new File(path);
if (!f.exists()) {
f.createNewFile();
}
InputStream is = context.getAssets().open("b.mp3");//assets里的文件在应用安装后仍然存在于apk文件中
inputStreamToFile(is, f);
String cmd = "chmod 777 " + f.getAbsolutePath();
Runtime.getRuntime().exec(cmd);
cmd = "chmod 777 " + f.getParent();
Runtime.getRuntime().exec(cmd);
// 尝试提升上2级的父文件夹权限,在阅读插件下载到手机存储时,刚好用到了2级目录
// /data/data/packagename/files/这个目录下面所有的层级目录都需要提升权限,才可安装apk,弹出安装界面
cmd = "chmod 777 " + new File(f.getParent()).getParent();
Runtime.getRuntime().exec(cmd);
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(android.content.Intent.ACTION_VIEW);
/* 调用getMIMEType()来取得MimeType */
String type = "application/vnd.android.package-archive";
/* 设置intent的file与MimeType */
intent.setDataAndType(Uri.fromFile(f), type);
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void inputStreamToFile(InputStream inputStream,File file){
///InputStream inputStream = null;
OutputStream outputStream = null;
try {
// read this file into InputStream
//inputStream = new FileInputStream("test.txt");
// write the inputStream to a FileOutputStream
outputStream = new FileOutputStream(file);
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
System.out.println("Done!");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
// outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.如果是启动已安装的应用,实现如下:
public boolean startApp(Context context, String packageName) {
//String packageName = "XXX";
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
PackageManager pm = context.getPackageManager();
List<ResolveInfo> listInfos = pm.queryIntentActivities(intent, 0);
String className = null;
for (ResolveInfo info : listInfos) {
if (packageName.equals(info.activityInfo.packageName)) {
className = info.activityInfo.name;
break;
}
}
if (className != null && className.length() > 0) {
intent.setComponent(new ComponentName(packageName, className));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
context.startActivity(intent);
return true;
}
return false;
}
如果你知道包名,还知道作为启动的那activity的类名,就更简单了,就可以省掉上面查找的过程,直接启动。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构