说明:Android 安装应用时都会调用系统本身自带的安装器,需要用户选择,查看权限才能安装,单个应用安装不会有太大的不适应, 若批量安装时就比较麻烦了,按到手酸.

本文的目的就是要自动安装应用, 不需要用户干预.

虽然最后也没有成功, 但过程大家可以借鉴下.

 

参考系统的安装器PackInstaller源码

得知系统有个隐藏API:

PackageManager 类的

public abstract void installPackage (Uri packageURI,IPackageInstallObserver observer,

 int flags, StringinstallerPackageName)

http://www.kiwidoc.com/java/l/x/android/android/5/p/android.content.pm/c/PackageManager

而使用这个隐藏API的方式,只有下载Android的源码, 编译得到framework.jar包.

下载源码和编译源码,都要在Ubuntu下完成, 这个过程非常麻烦, 我也试了其他方法

其实, 我们需要的就是一个framework.jar包, 我从模拟机里面给pull了一个出来, 发现不能用, 因为Android的系统都是用另外一种格式的 *.dex的 这个包里面也是.

尝试了其他很多方法, 结果都是失败了.

只好下载源码编译源码, 下载方法可以在网上找到.

这是网上关于使用隐藏API的叙述

在Android源码中,某些方法,成员,类或包(通过package.html文件)被打上@hide标签,这些类、方法或成员在SDK中没有公开,比如类android.app.ActivityThread,类android.text.method.Touch的getMaxScrollX()方法,类android.view.View的成员mScrollX等。因此在使用这些类时会提示类或成员不能被解决。下面提供一种方法解决这个问题。

首先,下载Android源码进行编译。然后在编译后的out目录下寻找包含你所用隐藏类的模块的jar文件,通常文件名为classes.jar。比如framework的jar文件为out"target"common"obj"JAVA_LIBRARIES"framework_intermediates"classes.jar。最后在eclipse的Android项目中,选择项目属性->Java Build Path->Libraries->Add Library->User Library->Next-> User Libraries进入到User Libraries管理界面,点击New新建一个User Library,比如android_framework,点击Add Jars把Jar包加入到建立的User Library中,最后点击OK就可以了。为了访问因此成员,需要改变类搜索顺序,选择项目属性->Java Build Path->Order and Export,把所建立的User Libraries移到Android SDK的上面。

隐藏API如果没有涉及到权限的应该都可以使用.

但巧合的是 InstallPackage 需要权限

<uses-permission android:name="android.permission.INSTALL_PACKAGES"></uses-permission>

这个权限只有获取系统签名的程序才可以使用.

这就悲剧了.

所谓的系统签名, 是指在ROM制作时, 使用ROM本身的数字签名文档进行签名. 不同的ROM有不同的数字签名. 所以即使在一个ROM上进行签名了, 在别的ROM上是无法运行的, 据说安装都安装不上.

网上关于加入系统权限的文章不少.

以下 引用: http://dev.10086.cn/blog/?uid-49302-action-viewspace-itemid-907

android 的API中有提供 SystemClock.setCurrentTimeMillis()函数来修改系统时间,可惜无论你怎么调用这个函数都是没用的,无论模拟器还是真机,在logcat中总会得到"Unable to open alarm driver: Permission denied ".这个函数需要root权限或者运行与系统进程中才可以用。

本来以为就没有办法在应用程序这一层改系统时间了,后来在网上搜了好久,知道这个目的还是可以达到的。

第一个方法简单点,不过需要在Android系统源码的环境下用make来编译:

1. 在应用程序的AndroidManifest.xml中的manifest节点中加入android:sharedUserId="android.uid.system"这个属性。

2. 修改Android.mk文件,加入LOCAL_CERTIFICATE := platform这一行

3. 使用mm命令来编译,生成的apk就有修改系统时间的权限了。

第二个方法麻烦点,不过不用开虚拟机跑到源码环境下用make来编译:

1. 同上,加入android:sharedUserId="android.uid.system"这个属性。

2. 使用eclipse编译出apk文件,但是这个apk文件是不能用的。

3. 用压缩软件打开apk文件,删掉META-INF目录下的CERT.SF和CERT.RSA两个文件。

4. 使用目标系统的platform密钥来重新给apk文件签名。这步比较麻烦,首先找到密钥文件,在我的Android源码目录中的位置是"build"target"product"security",下面的platform.pk8和platform.x509.pem两个文件。然后用Android提供的Signapk工具来签名,signapk的源代码是在"build"tools"signapk"下,用法为"signapk platform.x509.pem platform.pk8 input.apk output.apk",文件名最好使用绝对路径防止找不到,也可以修改源代码直接使用。

这样最后得到的apk和第一个方法是一样的。

最后解释一下原理,首先加入android:sharedUserId="android.uid.system"这个属性。通过Shared User id,拥有同一个User id的多个APK可以配置成运行在同一个进程中。那么把程序的UID配成android.uid.system,也就是要让程序运行在系统进程中,这样就有权限来修改系统时间了。

只是加入UID还不够,如果这时候安装APK的话发现无法安装,提示签名不符,原因是程序想要运行在系统进程中还要有目标系统的platform. key,就是上面第二个方法提到的platform.pk8和platform.x509.pem两个文件。用这两个key签名后apk才真正可以放入系统进程中。第一个方法中加入LOCAL_CERTIFICATE := platform其实就是用这两个key来签名。

这也有一个问题,就是这样生成的程序只有在原始的Android系统或者是自己编译的系统中才可以用,因为这样的系统才可以拿到platform.pk8和platform.x509.pem两个文件。要是别家公司做的Android上连安装都安装不了。试试原始的Android中的key来签名,程序在模拟器上运行OK,不过放到G3上安装直接提示"Package ... has no signatures that match those in shared user android.uid.system",这样也是保护了系统的安全。

最最后还说下,这个android:sharedUserId属性不只可以把apk放到系统进程中,也可以配置多个APK运行在一个进程中,这样可以共享数据,应该会很有用的。

所以说, 这是一个非常悲剧的事情---问题没有解决.