静默安装 收集
来源:互联网 发布:淘宝直播怎么加入 编辑:程序博客网 时间:2024/06/05 00:05
软件实现的功能:当需要静默安装(即不弹出安装确认对话框,后台自动安装)时,启动安装服务,将待安装的软件包的路径放置到intent中,然后启动安装服务即可,在软件成功安装以后,会发送广播,你只需要接受对应的广播,即可获知软件是否安装成功!
软件的关键代码:
Java代码
1. class PackageInstallObserver extends IPackageInstallObserver.Stub {
2. public void packageInstalled(String packageName, int returnCode) {
3. Intent intent = new Intent(Constants.ACTION_INSTALLED);
4. intent.putExtra(Constants.EXTRA_INSTALL_RESULT, returnCode);
5. intent.putExtra(Constants.EXTRA_PACKAGE_NAME, packageName);
6. String apkName = map.get(packageName);
7. if( apkName != null )intent.putExtra(Constants.EXTRA_APK_NAME, apkName);
8. mContext.sendBroadcast(intent);
9. }
10. }
这个类通过名字大概可以看出来,就是一个观察者,当安装成功或者失败的时候,就会调用该类的packageInstalled方法,因此,我们可以将安装成功或者失败的响应代码写在这里,上面的类就是发送广播,告诉别人软件安装成功。
Java代码
1. public void install(String apkPath,String apkName) {
2. File file = new File(apkPath);
3. if( !file.exists())
4. return ;
5. Uri mPackageURI = Uri.fromFile(file);
6. int installFlags = 0;
7. PackageManager pm = getPackageManager();
8. PackageInfo info = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
9. if(info != null){
10. try {
11. PackageInfo pi = pm.getPackageInfo(info.packageName,PackageManager.GET_UNINSTALLED_PACKAGES);
12. if( pi != null){
13. installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
14. }
15. } catch (NameNotFoundException e) {
16. }
17. //把包名和apkName对应起来,后面需要使用
18. map.put(info.packageName, apkName);
19. IPackageInstallObserver observer = new PackageInstallObserver();
20. pm.installPackage(mPackageURI, observer, installFlags, info.packageName);
21. }
22. }
这个方法就是关键的软件包安装方法,首先检查给定的软件安装包是否存在,后面的代码就是判断系统当前是否已经安装了该软件,如果已经安装了,则设置安装参数为替换。
pm.installPackage(mPackageURI, observer, installFlags, info.packageName);
这行代码调用PackageManager的installPackage方法进行软件包安装,并注册一个观察者。
另一种方式安装软件包,是通过发送intent请求,让系统来安装,所以我们无法控制安装提示界面。而该方式是自己直接调用系统的核心方法,跳过了安装确认界面,这样来实现静默安装。
分析,因为这个api是系统影藏api,直接调用会报错,因此这个应用需要到源码环境下才能编译成功,关键源码环境的搭建可以参考博客:http://www.2cto.com/kf/201204/128606.html。
另外,由于是调用了系统隐藏api,所以这个应用也必须安装到系统app目录下才能够调用成功。因此,使用这种方式适合这样的需求:第一,适合于内置到rom中,第二,或者是获取了系统root权限,然后将该app拷贝到system/app目录,并设置好权限,现在android手机基本都获取了root权限,这种方式也不难实现。
希望能给需要的人一点帮助~
============================================================================================================================
要求在安装APK应用时不显示权限信息和安装过程。
Google的安全策略要求任何应用应该提示APK安装包的权限,对于一些内置特定厂商应用,可以跳过安装过程的信息加快安装,或者运营商强制安装。
这个功能的实现在src/package/app/PackageInstaller中,需要修改。添加静默安装的功能。又兼容正常安装。
实现的分析
在窗口中点击一个APK时,触发单击事件,PackageInstaller接收系统服务PackageManagerService传来的intent信息,传来的Intent信息中有APK的一些参数。实现的关键是区分一般APK和特定APK。
通过传给PackageManagerService的intent中添加特别的参数,PackageInstaller接收后进行判断,进行特别的隐藏安装流程。这个实现只能通过程序调用的方式安装。
安装过程的信息窗口在PackageInstallActivity.java中实现的。安装过程的信息窗口有4个:需要实现一个PakkageInstallActivityHide.JAVA的文件,去掉下面的dialog和窗口
安装权限确认窗口:installPermissionConfirm
安装进度条:installProgress
安装结果窗口:installResult
安装错误提示对话框
文件列表大概如下:
InstallAppProgress.java
PackageInstallerActivity.java
+PackageInstallerActivityHide.java
PackageUtil.java
UninstallAppProgress.java
UninstallerActivity.java
+UninstallerActivityHide.java
具体实现
1 在Androidmainfest.xml声明一个特定的intent:android.intent.action.VIEW.HIDE,由PackageInstallActivityHide.java来接受
注意这里的两点:
- 把原先的 <application android:label="@string/app_name" android:theme="@android:style/Theme.Holo.DialogWhenLarge">
- 改成 <application android:label="@string/app_name">,
- 把android:theme="@android:style/Theme.Holo.DialogWhenLarge"主题的显示放在每一个<activity 中,兼容正常按装的UI主题不变
- 隐藏安装的PakkageInstallActivityHide <activity的主题只能是:
- android:theme="@android:style/Theme.NoDisplay" 只能是这个,没有窗口
内容如下:
- <application android:label="@string/app_name">
- <activity android:name=".PackageInstallerActivity" android:theme="@android:style/Theme.Holo.DialogWhenLarge" android:configChanges="orientation|keyboardHidden">
- <intent-filter>
- <action android:name="android.intent.action.VIEW"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <data android:scheme="content"/>
- <data android:scheme="file"/>
- <data android:mimeType="application/vnd.android.package-archive"/>
- </intent-filter>
- </activity>
- <activity android:name=".PackageInstallerHideActivity" android:theme="@android:style/Theme.NoDisplay" android:configChanges="orientation|keyboardHidden">
- <intent-filter>
- <action android:name="android.intent.action.VIEW.HIDE"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <data android:scheme="content"/>
- <data android:scheme="file"/>
- <data android:mimeType="application/vnd.android.package-archive"/>
- </intent-filter>
- </activity>
- <activity android:name=".UninstallerActivityHide" android:theme="@android:style/Theme.NoDisplay" android:configChanges="orientation|keyboardHidden" android:excludeFromRecents="true">
- <intent-filter>
- <action android:name="android.intent.action.VIEW"/>
- <action android:name="android.intent.action.DELETE.HIDE"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <data android:scheme="package"/>
- </intent-filter>
- </activity>
2 实现PakkageInstallActivityHide.java,UninstallerActivityHide.java。 只需把PakkageInstallActivity.java修改去掉dialog和对话框。
3 安装程序调用者发一个上面定义的intent即可。如下例子,静默安装/sdcard/hello.apk
卸载的方法类似。
- Intent install_hide_intent = new Intent("android.intent.action.VIEW.HIDE");
- install_hide_intent .setDataAndType(Uri.parse("file:///sdcard/hello.apk"),
- "application/vnd.android.package-archive");
- startActivityForResult(install_hide_intent, INSTALL_RUSULT);
4 注意,这个方法需要PackageInstall这个apk必须与系统一起编译。这个apk在/system/app/目录下面;android.intent.action.VIEW.HIDE 这个静默安装的接口需要开放给第三方。
===================================================================================================================(1)在网上搜寻该问题的解决方法,且查阅android开发文档,没有发现可以实现该功能的显示API调用,网络上很多人请教同样的问题,但都没有能够实现解答;说是android为了用户的安全,已屏蔽该实现该方法的功能,第三方法应用是无法实现静默安装的。
(2)然后自己试图去看看android实现普通安装程序的源码文件,能否找到解决的办法,打算绕过普通安装时的提示框,直接调用通过确认后调用的函数进行安装;在查看android应用程序的普通安装过程后,发现应用程序安装过程的方法调用过程为:首先进入到com/android/packageinstaller/PackageInstallerActivity.java这个Activity中,在这个Activity中首先检查所欲安装的程序是否是正确的安装文件,以及当前系统中是否已安装了此应用程序,提示用户是否重复安装,另外还获取所欲安装的程序所讲用到的权限,然后将这些信息通过一个对话框提示给用户,当用户确定安装时,启动com.android.packageinstaller.InstallAppProgress.java这个Activity,在这个Activity中,调用
android.content.pm.PackageManager.installPackage(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName)进行安装应用程序,在InstallAppProgress中得到的PackageManager是通过PackageManager pm = getPackageManager()得到的,得到的对象是一个android.app.ContextImpl.ApplicationPackageManager对象,而
ApplicationPackageManager对象经过封装,
ApplicationPackageManager(ContextImpl context,
IPackageManager pm) {
mContext = context;
mPM = pm;
}
其installPackage方法为
@Override
public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
String installerPackageName) {
try {
mPM.installPackage(packageURI, observer, flags, installerPackageName);
} catch (RemoteException e) {
// Should never happen!
}
}
可见调用的installPackage方法为 IPackageManager.installPackage(packageURI, observer, flags, installerPackageName);
在ContextImpl中,由IPackageManager pm = ActivityThread.getPackageManager()获得IPackageManager实例对象;在ActivityThread.getPackageManager()方法中,
static IPackageManager sPackageManager;
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
sPackageManager = IPackageManager.Stub.asInterface(b);
return sPackageManager;
}
最终得到的installPackage确实是IPackageManager.installPackage方法;
因为class PackageManagerService extends IPackageManager.Stub所以IPackageManager.installPackage调用的是:PackageManagerService.java (frameworks/base/services/java/com/android/server)文件中的
/* Called when a downloaded package installation has been confirmed by the user */
public void installPackage(
final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
installPackage(packageURI, observer, flags, null);
}
(这里不明白为何IPackageManager.installPackage方法调用的是PackageManagerService.java,只是在网上的一篇文章中它给出了上面的原因,因为class PackageManagerService extends IPackageManager.Stub,我不明白,但也找不到其他的函数,通过PackageManagerService.java的源码,可以看出它确实是进行应用程序安装的,所以应该可以确定最终调用的方法就是
PackageManagerService.installPackage(final Uri packageURI, final IPackageInstallObserver observer, final int flags))
于是考虑如何得到PackageManagerService.installPackage(),考虑通过反射的方法得到installPackage(),但其中难以得到的是其参数中的IPackageInstallObserver类型,IPackageInstallObserver是由aidl文件定义的,通过aidl文件的特性,将IPackageInstallObserver.aidl文件拷到本地程序中,可以得到类IPackageInstallObserver.calss,通过它反射出installPackage()方法,但在invoke该方法时,却无法得到IPackageInstallObserver的实例对象,IPackageInstallObserver的实例对象必须通过
IPackageInstallObserver.Stub.asInterface(IBinder binder)方式得到,无法得到与其绑定的IBinder对象,因而无法执行反射出来的方法;另外PackageManagerService.installPackage()似乎是不能被第三方应用程序执行的,有权限的限制,这从下面的实例中似乎可以得到证实。
(3)在程序中执行Runtime.getRuntime().exec("pm install -r " + new File(Environment.getExternalStorageDirectory(),
"download/Shuffle-1.6.3.apk")); 进行安装,这个命令的执行在 com.android.commands.pm.Pm中,直接调用IPackageManager.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,installerPackageName)方法,在此方法中,
IPackageManager mPm;
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
且class PackageManagerService extends IPackageManager.Stub
所以IPackageManager.installPackage调用的是:PackageManagerService.java (frameworks/base/services/java/com/android/server)文件中的
/* Called when a downloaded package installation has been confirmed by the user */
public void installPackage(
final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
installPackage(packageURI, observer, flags, null);
}
在此方法执行中会出现 Not granting permission android.permission.DELETE_PACKAGES错误,这应该是该权限不能授给第三方应用,因而在程序中不能执行,与android中普通安装应用程序最终调用的方法是相同的,但是却对第三方应用是没有权限执行的。。
(4) 另外解决思路:
1> 使用android:sharedUserId="android.uid.system"属性来使应用程序获得系统权限,看看是否能够执行行Runtime.getRuntime().exec("pm install -r ... ")方法。
2> 阅读android实现应用程序安装更底层的代码,看看能否可以调用的底层方法进行安装或者自己实现一个安装程序的代码,但这可能性不大,因为这涉及到android更底层的调用,
肯定会有一定的权限限制。
3> 在网上看到一个文件管理程序,据说是可以实现批量寂寞安装应用程序,但说明运行时需要用户确定得到手机的root权限,所以没有太大意义。
4> 定制自己的android系统,可以解决。
通常情况下,android是没有提供静默方式的上层接口,我们需要在android源代码下来调用这个隐藏的接口来完成静默安装。
最重要的就是参考android系统目录下的packages/apps/PackageInstaller,
当中有两个文件 PackageInstallerActivity.java,InstallAppProgress.java ,前者就是我们通常看到的带有提示对话框的安装应用程序,后者是点确定安装后调用的intent。
现提供一个静默安装的关键类,该类在android2.2下成功编译, 其中通过循环调用接口instatllBatch则可实现批量安装
当然最后的应用程序别忘记添加权限
1
<
uses-permission
android:name
=
"android.permission.WRITE_EXTERNAL_STORAGE"
/>
2
<
uses-permission
android:name
=
"android.permission.INSTALL_PACKAGES"
/>
3
<
uses-permission
android:name
=
"android.permission.DELETE_PACKAGES"
/>
4
<
uses-permission
android:name
=
"android.permission.CLEAR_APP_CACHE"
/>
5
<
uses-permission
android:name
=
"android.permission.READ_PHONE_STATE"
/>
6
<
uses-permission
android:name
=
"android.permission.CLEAR_APP_USER_DATA"
/>
001
package
com.android.util;
002
003
import
java.io.File;
004
005
import
java.io.FileNotFoundException;
006
007
import
java.io.FileOutputStream;
008
009
import
java.io.IOException;
010
011
import
android.content.Context;
012
013
import
android.content.Intent;
014
015
import
android.content.pm.PackageInfo;
016
017
import
android.content.pm.PackageManager;
018
019
import
android.content.pm.PackageManager.NameNotFoundException;
020
021
import
android.content.pm.ApplicationInfo;
022
023
import
android.content.pm.PackageParser;
024
025
import
android.net.Uri;
026
027
import
android.util.Log;
028
029
import
android.util.DisplayMetrics;
030
031
import
android.content.pm.IPackageInstallObserver;
032
033
import
android.content.pm.IPackageDeleteObserver;
034
035
import
android.os.FileUtils;
036
037
import
android.os.Handler;
038
039
import
android.os.Message;
040
041
042
043
public
class
PackageInstaller {
044
045
046
047
private
File mTmpFile;
048
049
private
final
int
INSTALL_COMPLETE =
1
;
050
051
final
static
int
SUCCEEDED =
1
;
052
053
final
static
int
FAILED =
0
;
054
055
private
final
static
String TAG =
"PackInstaller"
;
056
057
private
Context mContext;
058
059
private
ApplicationInfo mAppInfo;
060
061
public
PackageInstaller(Context context) {
062
063
mContext = context;
064
065
}
066
067
public
void
install(String path,String packageName){
068
069
Intent intent =
new
Intent(Intent.ACTION_VIEW);
070
071
intent.setDataAndType(Uri.fromFile(
new
File(path)),
072
073
"application/vnd.android.package-archive"
);
074
075
mContext.startActivity(intent);
076
077
}
078
079
080
081
public
void
instatllBatch(String path) {
082
083
Log.i(TAG,
"path="
+ path);
084
085
int
installFlags =
0
;
086
087
Uri mPackageURI = Uri.fromFile(
new
File(path));
088
089
PackageParser.Package mPkgInfo = getPackageInfo(mPackageURI);
090
091
mAppInfo = mPkgInfo.applicationInfo;
092
093
String packageName = mAppInfo.packageName;
094
095
Log.i(TAG,
"====install packageName ="
+packageName);
096
097
PackageManager pm = mContext.getPackageManager();
098
099
try
{
100
101
PackageInfo pi = pm.getPackageInfo(packageName,
102
103
PackageManager.GET_UNINSTALLED_PACKAGES);
104
105
if
(pi !=
null
) {
106
107
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
108
109
}
110
111
}
catch
(NameNotFoundException e) {
112
113
}
114
115
if
((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) !=
0
) {
116
117
Log.w(TAG,
"Replacing package:"
+ packageName);
118
119
}
120
121
122
123
PackageInstallObserver observer =
new
PackageInstallObserver();
124
125
pm.installPackage(mPackageURI, observer, installFlags,
126
127
packageName);
128
129
}
130
131
private
class
PackageInstallObserver
extends
IPackageInstallObserver.Stub {
132
133
public
void
packageInstalled(String packageName,
int
returnCode) {
134
135
// Message msg = mHandler.obtainMessage(INSTALL_COMPLETE);
136
137
// msg.arg1 = returnCode;
138
139
// mHandler.sendMessage(msg);
140
141
Log.i(TAG,
"====INSTALL_COMPLETE"
);
142
143
}
144
145
}
146
147
private
class
PackageDeleteObserver
extends
IPackageDeleteObserver.Stub {
148
149
public
void
packageDeleted(
boolean
succeeded) {
150
151
// Message msg = mHandler.obtainMessage(UNINSTALL_COMPLETE);
152
153
// msg.arg1 = succeeded?SUCCEEDED:FAILED;
154
155
// mHandler.sendMessage(msg);
156
157
Log.i(TAG,
"====UNINSTALL_COMPLETE"
);
158
159
}
160
161
}
162
163
public
void
uninstall(String packageName){
164
165
Uri packageURI = Uri.parse(
"package:"
+ packageName);
166
167
Intent uninstallIntent =
new
Intent(Intent.ACTION_DELETE,
168
169
packageURI);
170
171
mContext.startActivity(uninstallIntent);
172
173
}
174
175
176
177
public
void
uninstallBatch(String packageName) {
178
179
PackageDeleteObserver observer =
new
PackageDeleteObserver();
180
181
mContext.getPackageManager().deletePackage(packageName, observer,
0
);
182
183
184
185
}
186
187
/*
188
189
* Utility method to get package information for a given packageURI
190
191
*/
192
193
public PackageParser.Package getPackageInfo(Uri packageURI) {
194
195
final String archiveFilePath = packageURI.getPath();
196
197
PackageParser packageParser = new PackageParser(archiveFilePath);
198
199
File sourceFile = new File(archiveFilePath);
200
201
DisplayMetrics metrics = new DisplayMetrics();
202
203
metrics.setToDefaults();
204
205
PackageParser.Package pkg = packageParser.parsePackage(sourceFile,
206
207
archiveFilePath, metrics, 0);
208
209
// Nuke the parser reference.
210
211
packageParser = null;
212
213
return pkg;
214
215
}
216
217
/*
218
219
* Utility method to get application information for a given packageURI
220
221
*/
222
223
public
ApplicationInfo getApplicationInfo(Uri packageURI) {
224
225
final
String archiveFilePath = packageURI.getPath();
226
227
PackageParser packageParser =
new
PackageParser(archiveFilePath);
228
229
File sourceFile =
new
File(archiveFilePath);
230
231
DisplayMetrics metrics =
new
DisplayMetrics();
232
233
metrics.setToDefaults();
234
235
PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath, metrics,
0
);
236
237
if
(pkg ==
null
) {
238
239
return
null
;
240
241
}
242
243
return
pkg.applicationInfo;
244
245
}
246
247
private
Handler mHandler =
new
Handler() {
248
249
public
void
handleMessage(Message msg) {
250
251
switch
(msg.what) {
252
253
case
INSTALL_COMPLETE:
254
255
if
(msg.arg1 == SUCCEEDED) {
256
257
258
259
}
else
{}
260
261
break
;
262
263
default
:
264
265
break
;
266
267
}
268
269
}
270
271
};
272
273
}
- 静默安装 收集
- 静默安装 收集
- 静默安装
- 静默安装
- 静默安装
- 静默安装
- 静默安装
- 静默安装
- 静默安装
- 静默安装
- 静默安装
- 静默安装
- 静默安装
- 静默安装和静默卸载
- Android 静默升级,静默安装
- 静默安装apk,静默卸载apk
- android静默安装、静默卸载apk方法
- WINDOWS 下静默安装 与 静默卸载
- POJ 2492 A Bug's Life 并查集的应用
- tftp: command not found
- ubuntu12下安装golang和IDE
- Remove Duplicates from Sorted List
- RemoveDuplicatesFromSortedListII
- 静默安装 收集
- 八皇后问题—递归实现
- hdu4661 树形DP
- 二叉树两结点的最低共同父结点
- lightoj 1061 KM 二分图匹配
- centOS6.4 install crmsh, old opensuse repository is useless
- 硬链接
- HDU-1312-red and black
- 怎么提高Mysql执行sql导入的速度