在使用静默安装的时候,一般需要满足一定的苛刻条件。
网上流传的方法有:
1. app具有系统签名(和framwork签名一致)
或
2.app在system/app/目录下,具体的步骤如下:
分为如下三步
(1)、静默安装需要系统应用安装权限,需要在AndroidManifest.xml中添加
1
|
<
uses
-
permission
android
:
name
=
"android.permission.INSTALL_PACKAGES"
/
>
|
(2)、实现代码
静默安装代码如下,实际是通过pm install -r 命令安装。
注意:该函数最好在新建的线程中运行并通过handler发送安装结果给主线程,否则安装时间较长会导致ANR。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
/**
* install slient
*
* @param context
* @param filePath
* @return 0 means normal, 1 means file not exist, 2 means other exception error
*/
public
static
int
installSlient
(
Context
context
,
String
filePath
)
{
File
file
=
new
File
(
filePath
)
;
if
(
filePath
==
null
||
filePath
.
length
(
)
==
0
||
(
file
=
new
File
(
filePath
)
)
==
null
||
file
.
length
(
)
<=
0
||
!
file
.
exists
(
)
||
!
file
.
isFile
(
)
)
{
return
1
;
}
String
[
]
args
=
{
"pm"
,
"install"
,
"-r"
,
filePath
}
;
ProcessBuilder
processBuilder
=
new
ProcessBuilder
(
args
)
;
Process
process
=
null
;
BufferedReader
successResult
=
null
;
BufferedReader
errorResult
=
null
;
StringBuilder
successMsg
=
new
StringBuilder
(
)
;
StringBuilder
errorMsg
=
new
StringBuilder
(
)
;
int
result
;
try
{
process
=
processBuilder
.
start
(
)
;
successResult
=
new
BufferedReader
(
new
InputStreamReader
(
process
.
getInputStream
(
)
)
)
;
errorResult
=
new
BufferedReader
(
new
InputStreamReader
(
process
.
getErrorStream
(
)
)
)
;
String
s
;
while
(
(
s
=
successResult
.
readLine
(
)
)
!=
null
)
{
successMsg
.
append
(
s
)
;
}
while
(
(
s
=
errorResult
.
readLine
(
)
)
!=
null
)
{
errorMsg
.
append
(
s
)
;
}
}
catch
(
IOException
e
)
{
e
.
printStackTrace
(
)
;
result
=
2
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
(
)
;
result
=
2
;
}
finally
{
try
{
if
(
successResult
!=
null
)
{
successResult
.
close
(
)
;
}
if
(
errorResult
!=
null
)
{
errorResult
.
close
(
)
;
}
}
catch
(
IOException
e
)
{
e
.
printStackTrace
(
)
;
}
if
(
process
!=
null
)
{
process
.
destroy
(
)
;
}
}
// TODO should add memory is not enough here
if
(
successMsg
.
toString
(
)
.
contains
(
"Success"
)
||
successMsg
.
toString
(
)
.
contains
(
"success"
)
)
{
result
=
0
;
}
else
{
result
=
2
;
}
Log
.
d
(
"installSlient"
,
"successMsg:"
+
successMsg
+
", ErrorMsg:"
+
errorMsg
)
;
return
result
;
}
|
返回值0表示安装成功,1表示文件不存在,2表示其他错误。需要更丰富的安装失败信息(内存不足、解析包出错)可直接使用PackageUtils.installSlient。
(3) 、获取系统权限
完成了上面两步后,普通方式安装我们的应用仍然无法静默安装。需要我们的应用获得系统权限,编译应用并通过
adb push <your_apk_path> /system/app/
命令实现安装,即可拥有系统权限。
但是实际上呢,第二种方式在android4.4以后的机子上都无法实现了。因为在4.4中增加了目录system/priv-app/ 这个目录下的app是具备比system/app/下更高的权限。
/system/priv-app中包括Launcher,systemui, settingsprovider等,均是系统的核心应用,这些应用能使用系统级的权限,4.4之前的所有/system/app下的软件都能使用系统级的权限。 Google这样做是把内置到系统的应用也做个级别的区别。 放到/system/priv-app下的应用比放到/system/app下的应用可以声明获得更多的权限。因为定义权限的的时候有protectionLevel字段限制权限的使用.它有四种值 normal dangerous signatrue signatureOrSystem。/system/priv-app符合signatureOrSystem的限制 |
在framework的AndroidManifest.xml中定义了INSTALL_PACKAGES的权限级别:
可以看到是signature|privileged最高级别的(signatureOrSystem)。
实践中发现,只要把我们的app放入到system/priv-app/目录下,就能自动获取这个权限了。(放入system/app/目录下是不行的)。直接可以实现静默安装(不需要什么系统签名了)
但是如果我使用了系统签名(判断是否系统签名的条件是代码检测install_packages这个权限是否有获取到),代码检测能有这个权限,但是如果不把app放到这两个目录下面,依旧不能实现静默安装。
这个是系统签名后通过adb shell dumpsys package -p com.xx.xx获取到的install权限:
可以看出权限已经有了,但是还是不能执行静默安装。
那么也就是说,在我司的系统中,静默安装的必要条件必须是在system/priv-app/(在该目录下自动获取了install权限(不需要签名就能获取到))或者system/app/+install权限(通过签名获取)目录下了。
而当前我的app的一个需求就是自动检测是否有静默安装的能力,所以就得判断我的app是否满足以上两个条件中的一个
所以就有了下面这方法:
public static boolean isSystemApp(){
if ((mAppContext.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
LogUtils.d("AppContextUtils","是系统应用");
return true;
}
LogUtils.d("AppContextUtils", "非系统应用");
return false;
}
实际上,放在system/app/和system/priv-app/目录下的都会标记为FLAG_SYSTEM。
当然,如果我们只判断这个条件的话,在/system/app/目录下满足这个条件,但是如果没有系统签名的话不满足install权限,也就是说在此基础上还要加上install权限的检测。
public boolean hasInstallPermission(){
if(AppContextUtils.isSystemApp() &&
(ActivityCompat.checkSelfPermission(AppContextUtils.getAppContext(), "android.permission.INSTALL_PACKAGES") == PackageManager.PERMISSION_GRANTED)){
LogUtils.d(tag, "具备静默安装能力");
return true;
}else{
return false;
}
}
加上权限检查,这样双重保证就能确定是否有静默安装能力了。
这里还列举了其他方法: http://blog.csdn.net/w6028819321/article/details/12775999 目前来看,并不靠谱。