需求是这样的:我们的浏览器下载一个APK文件,把文件的下载路径交给系统的下载管理类:DownloadManager了,然后监听到下载完成后,就提示用户安装,弹出那个安装应用的界面。就是类似你从各个应用市场下载完应用后,也会提示你安装应用的。
你可以监听下载DownloadManager 的ACTION_DOWNLOAD_COMPLETE 这个ACTION,然后做你的逻辑处理,这个时候这个APK是没有安装的,如果想拿到应用的信息(
versionCode, versionName, appIcon, packageName等)怎么取到呢?
1.先做第一个实验:有2个应用A,B,都以及安装好了,我想在B中拿到A的应用信息,就是上面标红色的信息:我做了实验,用下面的方法可以取到。
获取已安装apk的信息,这里比较简单,网上的资料也非常多,就不做过的的介绍
private String getInstallAPKInfo(Context ctx,String pak) {
//pak=com.aa.bb
String versionName = null;
PackageManager pm=ctx.getPackageManager();
PackageInfo pakinfo;
try {
pakinfo = pm.getPackageInfo(pak, PackageManager.GET_ACTIVITIES);
if (pakinfo!=null) {
versionName=pakinfo.versionName;
}
//pak=com.aa.bb
String versionName = null;
PackageManager pm=ctx.getPackageManager();
PackageInfo pakinfo;
try {
pakinfo = pm.getPackageInfo(pak, PackageManager.GET_ACTIVITIES);
if (pakinfo!=null) {
versionName=pakinfo.versionName;
}
// 测试后发现,下面这样能取到,直接调用loadIcon
// Drawable icon = pakinfo.applicationInfo.loadIcon(pm);
// img.setBackgroundDrawable(icon);
// img.setBackgroundDrawable(icon);
// 测试后发现这样是取不到的,返回的是android的默认小绿色机器人的图标
// 分析:可能传进去的content是B应用的context, 所以在B应用中无法得到A应用的icon,返回默认的logo。
int iconId = pakinfo.applicationInfo.icon;
Drawable icon2 = ctx.getResources().getDrawable(iconId);
img.setBackgroundDrawable(icon2);
int iconId = pakinfo.applicationInfo.icon;
Drawable icon2 = ctx.getResources().getDrawable(iconId);
img.setBackgroundDrawable(icon2);
// 测试后,发现这样也能取到
Drawable icon3 = pm.getApplicationIcon(packageName);
img.setBackgroundDrawable(icon3);
img.setBackgroundDrawable(icon3);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return versionName;
}
2. 第二个实验,。在一个已经安装的APK中获取另一个未安装的APK的信息
下载的代码是网上都在传的,我做了2个测试,发现有点意思,一个测试是在系统应用中编译的,在android源码中直接mm编译的,按照下面的方法是可以取到的; 另一个是在一个普通的android项目中(就是新建一个Android Project),就取不到,我不知道这是否和系统签名的应用有关系。也看到网上有朋友说下面的代码根本取不到,也许他也是和我的第二个测试方法一样,在一个独立的app项目中测试的。
/**
* get un-installed apk package info
* @param ctx
* @param archiveFilePath
* @return
*/
private static String getUninstallAPKInfo(Context ctx,String archiveFilePath, TextView txt, ImageView img) {
// archiveFilePath=Environment.getExternalStorageDirectory()+"/"+"TestB.apk"
String versionName = null;
String appName = null;
String pakName = null;
PackageManager pm = ctx.getPackageManager();
PackageInfo pakinfo = pm.getPackageArchiveInfo(archiveFilePath, PackageManager.GET_ACTIVITIES);
if (pakinfo != null) {
ApplicationInfo appinfo=pakinfo.applicationInfo;
versionName = pakinfo.versionName;
Drawable icon=pm.getApplicationIcon(appinfo);
appName = (String) pm.getApplicationLabel(appinfo);
pakName = appinfo.packageName;
String text = "versionName = " + versionName + " , appName = " + appName + " , pakName = " + pakName;
txt.setText(text);
img.setBackgroundDrawable(icon);
} else {
System.out.println("pakinfo == null");
}
return versionName;
}
* get un-installed apk package info
* @param ctx
* @param archiveFilePath
* @return
*/
private static String getUninstallAPKInfo(Context ctx,String archiveFilePath, TextView txt, ImageView img) {
// archiveFilePath=Environment.getExternalStorageDirectory()+"/"+"TestB.apk"
String versionName = null;
String appName = null;
String pakName = null;
PackageManager pm = ctx.getPackageManager();
PackageInfo pakinfo = pm.getPackageArchiveInfo(archiveFilePath, PackageManager.GET_ACTIVITIES);
if (pakinfo != null) {
ApplicationInfo appinfo=pakinfo.applicationInfo;
versionName = pakinfo.versionName;
Drawable icon=pm.getApplicationIcon(appinfo);
appName = (String) pm.getApplicationLabel(appinfo);
pakName = appinfo.packageName;
String text = "versionName = " + versionName + " , appName = " + appName + " , pakName = " + pakName;
txt.setText(text);
img.setBackgroundDrawable(icon);
} else {
System.out.println("pakinfo == null");
}
return versionName;
}
上面的源码这个链接中有:http://blog.csdn.net/johnsonblog/article/details/7604899
补充:获取未安装APK的签名信息,和获取versionCode其实差不多~
http://www.blogjava.net/TiGERTiAN/archive/2012/05/27/379322.html
到这里就涉及到Android 动态加载了
动态加载主要是加载未安装或者以及安装但是没有启动的应用的类或者资源文件。
1.这个老兄的这个博文应该是比较有价值的,通过反射获得未安装的APK的资源,比如:appIcon, versionName, packageName等;
http://kalogen.iteye.com/?page=3
里面提到的这个以及无法点击了,其实我看了下,就是这个类:packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
借鉴的Android源码出处:
2.用反射调用其他APP里的函数和资源
http://blog.sina.com.cn/s/blog_7bed7b2b01015dc0.html
http://blog.sina.com.cn/s/blog_7bed7b2b010169se.html
http://www.cnblogs.com/over140/archive/2011/11/23/2259367.html
http://www.cnblogs.com/over140/archive/2012/03/29/2423116.html
http://www.cnblogs.com/over140/archive/2012/04/19/2446119.html
http://www.blogjava.net/zh-weir/archive/2012/03/29/362294.html
http://wangleyiang.iteye.com/blog/1791947
http://blog.csdn.net/johnsonblog/article/details/7581070
4.补充:
为了测试动态加载,启动未安装的APK中的类,我根据下面文章做测试, 我开始把测试的3个apk 文件:TestRoomA, TestRoomB, TestRoomC放到/data/data/com.anhuioss.hall/apk/ 下,报这个错误,我又改到/storage/xxx/ 下,也报这个错误,后来没办法就看网上的答案,有个兄弟说放这里是可以的:
拷贝文件到/data/data/包名 目录下即可解决此问题,经过测试确实可以了。
但是一直发现下面的问题,似乎是没有权限的问题,百度了一下,果然是这样的,在android4.1的时候改的:(
答案见链接)
java.lang.IllegalArgumentException: Optimized data directory /storage/sdcard0 is not owned by the current user. Shared storage cannot protect your application from code injection attacks.
参考答案链接:
http://www.oschina.net/question/162135_93054
最后总结,这种技术是否成熟,需要待定~需要做多次测试才好~