Android 静默安装和智能安装的实现方法

http://www.2cto.com/kf/201607/524590.html


1 简介

最近研究了Android的静默安装和智能安装,于是写博客记录一下。静默安装就是无声无息的在后台安装apk,没有任何界面提示。智能安装就是有安装界面,但全部是自动的,不需要用户去点击。
首先强调两点:静默安装必须要root权限 智能安装必须要用户手动开启无障碍服务

2 原理

静默安装、卸载的原理就是利用pm install命令来安装apk,pm uninstall 来卸载apk. 智能安装是利用android系统提供的无障碍服务AccessibilityService,来模拟用户点击,从而自动安装.

3 pm命令介绍

(1) pm install
pm install 命令的用法及参数解释如下:

?
1
2
3
4
5
6
7
8
9
<code class = "hljs haml" >pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH
 
Options:
   -l: install the package with FORWARD_LOCK.
   -r: reinstall an exisiting app, keeping its data.
   -t: allow test .apks to be installed.
   -i: specify the installer package name.
   -s: install package on sdcard.
   -f: install package on internal flash.</code>

(2) pm uninstall
pm uninstall 命令的用法及参数解释如下:

?
1
2
3
4
<code class = "hljs livecodeserver" >pm uninstall [-k] PACKAGE
 
Options:
   -k: keep the data and cache directories around.</code>

上面英语很简单,不解释了.

4 静默安装

为了方便演示,我把爱奇艺的安装包重命名为test.apk后放在了sdcard上。你可以自己去爱奇艺官网去下载,也可以自己找一个apk放到sdcard上,但是要知道apk的包名,后面卸载的时候要用到。
先上代码:

?
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
<code class = "hljs cs" > //静默安装
     private void installSlient() {
         String cmd = "pm install -r /mnt/sdcard/test.apk" ;
         Process process = null ;
         DataOutputStream os = null ;
         BufferedReader successResult = null ;
         BufferedReader errorResult = null ;
         StringBuilder successMsg = null ;
         StringBuilder errorMsg = null ;
         try {
             //静默安装需要root权限
             process = Runtime.getRuntime().exec( "su" );
             os = new DataOutputStream(process.getOutputStream());
             os.write(cmd.getBytes());
             os.writeBytes( "\n" );
             os.writeBytes( "exit\n" );
             os.flush();
             //执行命令
             process.waitFor();
             //获取返回结果
             successMsg = new StringBuilder();
             errorMsg = new StringBuilder();
             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 (Exception e) {
             e.printStackTrace();
         } finally {
             try {
                 if (os != null ) {
                     os.close();
                 }
                 if (process != null ) {
                     process.destroy();
                 }
                 if (successResult != null ) {
                     successResult.close();
                 }
                 if (errorResult != null ) {
                     errorResult.close();
                 }
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
         //显示结果
         tvTest.setText( "成功消息:" + successMsg.toString() + "\n" + "错误消息: " + errorMsg.toString());
     }</code>

这段代码就是在程序中执行pm命令,和在adb下执行 pm install -r /mnt/sdcard/test.apk 效果是一样的, 关键的代码是 Runtime.getRuntime().exec(“su”) ,这段代码会要求获取root权限,所以你的手机必须root,不想root的话,直接用模拟器也可以。

通过 Runtime.getRuntime().exec(“su”) 获取到 process 对象后就可以写入命令了,每写入一条命令就要换行,写入 ‘\n’ 即可,最后写入exit后离开命令执行的环境.

5 静默卸载

静默卸载和静默安装是一样的,只是命令不同,静默卸载需要用到包名,同样,静默卸载也需要root权限
看代码:

?
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
<code class = "hljs java" > //爱奇艺apk的包名
private static final String PACKAGE_NAME = "com.qiyi.video" ;
//静默卸载
     private void uninstallSlient() {
         String cmd = "pm uninstall " + PACKAGE_NAME;
         Process process = null ;
         DataOutputStream os = null ;
         BufferedReader successResult = null ;
         BufferedReader errorResult = null ;
         StringBuilder successMsg = null ;
         StringBuilder errorMsg = null ;
         try {
             //卸载也需要root权限
             process = Runtime.getRuntime().exec( "su" );
             os = new DataOutputStream(process.getOutputStream());
             os.write(cmd.getBytes());
             os.writeBytes( "\n" );
             os.writeBytes( "exit\n" );
             os.flush();
             //执行命令
             process.waitFor();
             //获取返回结果
             successMsg = new StringBuilder();
             errorMsg = new StringBuilder();
             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 (Exception e) {
             e.printStackTrace();
         } finally {
             try {
                 if (os != null ) {
                     os.close();
                 }
                 if (process != null ) {
                     process.destroy();
                 }
                 if (successResult != null ) {
                     successResult.close();
                 }
                 if (errorResult != null ) {
                     errorResult.close();
                 }
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
         //显示结果
         tvTest.setText( "成功消息:" + successMsg.toString() + "\n" + "错误消息: " + errorMsg.toString());
     }</code>

和静默安装一样的代码就不解释了。还有,如果你不知道一个apk的包名,那么请反编译后去看AndroidManifest.xml文件,如果这个文件打开全是乱码,说明是被混淆过的,那么直接安装它,然后到/data/data下面去找它的包,当然,手机得root才能进/data/data目录。

6 智能安装

智能安装就稍微麻烦点了,原理是用到了android提供的AccessibilityService服务,这个服务可以获取屏幕上的节点,一个节点也就是一个view,我们写的xml文件中每个标签就是一个节点,然后可以模拟用户的操作,对这些节点进行点击、滑动等操作。我们就是利用这个原理,来自动点击安装按钮的,当然使用这个服务必须用户手动开启无障碍服务。下面我们来看具体的实现方法。

(1) 创建AccessibilityService配置文件 
在res目录下创建xml目录,然后在xml目录下创建一个accessibility_service_config.xml文件,内容如下
res/xml/accessibility_service_config.xml:

?
1
<code class = "hljs xml" ></accessibility-service></code>

accessibilityEventTypes:指定我们在监听窗口中可以模拟哪些事件,typeAllMask表示所有的事件都能模拟.
accessibilityFeedbackType:指定无障碍服务的反馈方式.
canRetrieveWindowContent:指定是否允许我们的程序读取窗口中的节点和内容,当然是true.
description: 当用户手动配置服务时,会显示给用户看.
packageNames: 指定我们要监听哪个应用程序下的窗口活动,这里写com.android.packageinstaller表示监听Android系统的安装界面。
其余参数照写即可。
res/strings.xml:

?
1
2
3
4
<code class = "hljs xml" ><resources>
     <string name= "app_name" >SlientInstallTest</string>
     <string name= "desc" >智能安装app功能演示</string>
</resources></code>

(2) 创建AccessibilityService服务

?
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
<code class = "hljs java" > public class MyAccessibilityService extends AccessibilityService {
 
     private static final String TAG = "[TAG]" ;
     private Map<integer, boolean = "" > handleMap = new HashMap<>();
 
     @Override
     public void onAccessibilityEvent(AccessibilityEvent event) {
         AccessibilityNodeInfo nodeInfo = event.getSource();
         if (nodeInfo != null ) {
             int eventType = event.getEventType();
             if (eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED || eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
                 if (handleMap.get(event.getWindowId()) == null ) {
                     boolean handled = iterateNodesAndHandle(nodeInfo);
                     if (handled) {
                         handleMap.put(event.getWindowId(), true );
                     }
                 }
             }
 
         }
     }
 
     @Override
     public void onInterrupt() {
 
     }
 
     //遍历节点,模拟点击安装按钮
     private boolean iterateNodesAndHandle(AccessibilityNodeInfo nodeInfo) {
         if (nodeInfo != null ) {
             int childCount = nodeInfo.getChildCount();
             if ( "android.widget.Button" .equals(nodeInfo.getClassName())) {
                 String nodeCotent = nodeInfo.getText().toString();
                 Log.d(TAG, "content is: " + nodeCotent);
                 if ( "安装" .equals(nodeCotent) || "完成" .equals(nodeCotent) || "确定" .equals(nodeCotent)) {
                     nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                     return true ;
                 }
             }
             //遇到ScrollView的时候模拟滑动一下
             else if ( "android.widget.ScrollView" .equals(nodeInfo.getClassName())) {
                 nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
             }
             for ( int i = 0 ; i < childCount; i++) {
                 AccessibilityNodeInfo childNodeInfo = nodeInfo.getChild(i);
                 if (iterateNodesAndHandle(childNodeInfo)) {
                     return true ;
                 }
             }
         }
         return false ;
     }
}</integer,></code>

当进入apk安装界面就会回调onAccessibilityEvent()这个方法,我们只关心TYPE_WINDOW_CONTENT_CHANGED和TYPE_WINDOW_STATE_CHANGED两个事件,为了防止重复处理事件,用一个map来过滤事件,后面递归遍历节点,找到’安装’ ‘完成’ ‘确定’ 的按钮,就点击,由于安装界面需要滚动一下才能出现安装按钮,所以遇到ScrollView的时候就滚动一下.

(3) 在AndroidManifest中配置服务

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<code class = "hljs xml" ><uses-permission android:name= "android.permission.READ_EXTERNAL_STORAGE" >
 
     
         
             <intent-filter>
                 
 
                 <category android:name= "android.intent.category.LAUNCHER" >
             </category></action></intent-filter>
         </activity>
 
         <service android:label= "智能安装App" android:name= ".MyAccessibilityService" android:permission= "android.permission.BIND_ACCESSIBILITY_SERVICE" >
             <intent-filter>
                 
             </action></intent-filter>
             <meta-data android:name= "android.accessibilityservice" android:resource= "@xml/accessibility_service_config" >
         </meta-data></service>
     </application></uses-permission></code>

重点是后面的service标签:
android:label:这个就是用户看到的无障碍服务的名称
android:permission: 需要用到BIND_ACCESSIBILITY_SERVICE这个权限.
action: android.accessibilityservice.AccessibilityService 有了这个action,用户才能在设置里面看到我们的服务,否则用户无法开启我们写的服务,也就不能进到我们写的MyAccessibilityService里面了.所以,注意不要写错了,如果你发现无障碍服务里面没有我们写的服务,请检查这里.

(4) 调用智能安装代码
前面准备工作完毕后,现在要用了,调用智能安装的代码如下:

?
1
2
3
4
5
6
7
<code class = "hljs cs" > //智能安装
     private void smartInstall() {
         Uri uri = Uri.fromFile( new File( "/mnt/sdcard/test.apk" ));
         Intent localIntent = new Intent(Intent.ACTION_VIEW);
         localIntent.setDataAndType(uri, "application/vnd.android.package-archive" );
         startActivity(localIntent);
     }</code>

(5) 手动配置智能安装服务
代码运行之后,还要用户选择开启智能安装服务,让用户自己去找是不明智的,因此,我们要主动跳到配置界面,代码如下:

?
1
2
3
<code class = "hljs cs" > //跳转到开启智能安装服务的界面
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivity(intent);</code>

配置如下图:

这里写图片描述

看到了吗,上面显示的就是Service里面的label的值,如果你没有上面的选项,请检查AndroidManifest里面Service的配置.
点击’智能安装App’,开启服务,如下图:

这里写图片描述

其中的提示文字就是我们在res/xml/accessibility_service_config.xml文件中配置的description属性

7 只能我们写的app可以自动安装

这样写完代码可以运行,点击按钮自动安装sdcard上的test.apk.但是你会发现,所有apk都会自动安装,这就不符合我们的要求了,我们要求只能通过我们写的app来自动安装,其他apk还是要用户手动去点。怎么解决这个问题呢?
思路是:在MainActivity中创建一个public static boolean flag,在MyAccessibilityService的onAccessibilityEvent()中加一个flag判断,然后调用智能安装前flag设为true,创建apk安装事件的广播接收器,当apk安装完成后,设置falg为false,这样其他apk就不能自动安装了,就解决了这个问题
下面上完整代码.

8 完整代码

app/MainActivity.java:

?
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
<code class = "hljs java" > public class MainActivity extends AppCompatActivity implements View.OnClickListener {
 
     private static final String TAG = "[TAG][MainActivity]" ;
     private static final String PACKAGE_NAME = "com.qiyi.video" ;
     private String apkPath = "/mnt/sdcard/test.apk" ;
     public static boolean flag = false ; //控制只能自己的app才能执行智能安装
     private TextView tvTest;
     private MyInstallReceiver receiver;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         tvTest = (TextView) findViewById(R.id.tv_test);
         findViewById(R.id.btn_install).setOnClickListener( this );
         findViewById(R.id.btn_uninstall).setOnClickListener( this );
         findViewById(R.id.btn_set).setOnClickListener( this );
         findViewById(R.id.btn_smart_install).setOnClickListener( this );
         //注册apk安装监听
         receiver = new MyInstallReceiver();
         IntentFilter filter = new IntentFilter();
         filter.addAction( "android.intent.action.PACKAGE_ADDED" );
         filter.addAction( "android.intent.action.PACKAGE_REMOVED" );
         filter.addDataScheme( "package" );
         this .registerReceiver(receiver, filter);
     }
 
 
     @Override
     public void onClick(View v) {
         switch (v.getId()) {
             //静默安装
             case R.id.btn_install:
                 installSlient();
                 break ;
             //静默卸载
             case R.id.btn_uninstall:
                 uninstallSlient();
                 break ;
             //设置无障碍服务
             case R.id.btn_set:
                 //跳转到开启无障碍服务的界面
                 Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
                 startActivity(intent);
                 break ;
             //智能安装
             case R.id.btn_smart_install:
                 //控制只能自己的app才能智能安装
                 flag = true ;
                 smartInstall();
                 break ;
         }
     }
 
     //静默安装
     private void installSlient() {
         String cmd = "pm install -r /mnt/sdcard/test.apk" ;
         Process process = null ;
         DataOutputStream os = null ;
         BufferedReader successResult = null ;
         BufferedReader errorResult = null ;
         StringBuilder successMsg = null ;
         StringBuilder errorMsg = null ;
         try {
             //静默安装需要root权限
             process = Runtime.getRuntime().exec( "su" );
             os = new DataOutputStream(process.getOutputStream());
             os.write(cmd.getBytes());
             os.writeBytes( "\n" );
             os.writeBytes( "exit\n" );
             os.flush();
             //执行命令
             process.waitFor();
             //获取返回结果
             successMsg = new StringBuilder();
             errorMsg = new StringBuilder();
             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 (Exception e) {
             e.printStackTrace();
         } finally {
             try {
                 if (os != null ) {
                     os.close();
                 }
                 if (process != null ) {
                     process.destroy();
                 }
                 if (successResult != null ) {
                     successResult.close();
                 }
                 if (errorResult != null ) {
                     errorResult.close();
                 }
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
         //显示结果
         tvTest.setText( "成功消息:" + successMsg.toString() + "\n" + "错误消息: " + errorMsg.toString());
     }
 
     //静默卸载
     private void uninstallSlient() {
         String cmd = "pm uninstall " + PACKAGE_NAME;
         Process process = null ;
         DataOutputStream os = null ;
         BufferedReader successResult = null ;
         BufferedReader errorResult = null ;
         StringBuilder successMsg = null ;
         StringBuilder errorMsg = null ;
         try {
             //卸载也需要root权限
             process = Runtime.getRuntime().exec( "su" );
             os = new DataOutputStream(process.getOutputStream());
             os.write(cmd.getBytes());
             os.writeBytes( "\n" );
             os.writeBytes( "exit\n" );
             os.flush();
             //执行命令
             process.waitFor();
             //获取返回结果
             successMsg = new StringBuilder();
             errorMsg = new StringBuilder();
             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 (Exception e) {
             e.printStackTrace();
         } finally {
             try {
                 if (os != null ) {
                     os.close();
                 }
                 if (process != null ) {
                     process.destroy();
                 }
                 if (successResult != null ) {
                     successResult.close();
                 }
                 if (errorResult != null ) {
                     errorResult.close();
                 }
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
         //显示结果
         tvTest.setText( "成功消息:" + successMsg.toString() + "\n" + "错误消息: " + errorMsg.toString());
     }
 
     //智能安装
     private void smartInstall() {
         Uri uri = Uri.fromFile( new File(apkPath));
         Intent localIntent = new Intent(Intent.ACTION_VIEW);
         localIntent.setDataAndType(uri, "application/vnd.android.package-archive" );
         startActivity(localIntent);
     }
 
     //监听apk安装
     private class MyInstallReceiver extends BroadcastReceiver {
 
         @Override
         public void onReceive(Context context, Intent intent) {
             if (intent.getAction().equals( "android.intent.action.PACKAGE_ADDED" )) {     // install
                 String packageName = intent.getDataString();
                 Log.i(TAG, "安装了 :" + packageName);
                 //安装完毕,设置flag,从而使得其余的apk不能自动安装
                 flag = false ;
             }
             if (intent.getAction().equals( "android.intent.action.PACKAGE_REMOVED" )) {   // uninstall
                 String packageName = intent.getDataString();
                 Log.i(TAG, "卸载了 :" + packageName);
             }
         }
     }
 
     @Override
     protected void onDestroy() {
         super .onDestroy();
         if (receiver != null ) {
             unregisterReceiver(receiver);
         }
     }
}</code>

界面上就三个按钮
res/layout/activity_main.xml:

?
1
2
3
4
5
6
<code class = "hljs xml" ><!--?xml version= "1.0" encoding= "utf-8" ?-->
<relativelayout android:layout_height= "match_parent" android:layout_width= "match_parent" android:paddingbottom= "@dimen/activity_vertical_margin" android:paddingleft= "@dimen/activity_horizontal_margin" android:paddingright= "@dimen/activity_horizontal_margin" android:paddingtop= "@dimen/activity_vertical_margin" xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http://schemas.android.com/tools" >
 
     <textview android:id= "@+id/tv_test" android:layout_height= "wrap_content" android:layout_width= "match_parent" android:text= "" ><button android:id= "@+id/btn_install" android:layout_centerinparent= "true" android:layout_height= "wrap_content" android:layout_width= "match_parent" android:text= "安装" ></button><button android:id= "@+id/btn_uninstall" android:layout_below= "@id/btn_install" android:layout_height= "wrap_content" android:layout_width= "match_parent" android:text= "卸载" ></button><button android:id= "@+id/btn_set" android:layout_below= "@id/btn_uninstall" android:layout_height= "wrap_content" android:layout_width= "match_parent" android:text= "开启智能安装功能" ></button></textview></relativelayout></code><button android:id= "@+id/btn_smart_install" android:layout_below= "@id/btn_set" android:layout_height= "wrap_content" android:layout_width= "match_parent" android:text= "智能安装" ><code class = "hljs xml" >
 
</code></button>

服务配置文件
res/xml/accessibility_service_config.xml

?
1
<code class = "hljs xml" ></accessibility-service></code>

智能安装服务
app/MyAccessibilityService.java:

?
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
<code class = "hljs java" > public class MyAccessibilityService extends AccessibilityService {
 
     private static final String TAG = "[TAG]" ;
     private Map<integer, boolean = "" > handleMap = new HashMap<>();
 
     @Override
     public void onAccessibilityEvent(AccessibilityEvent event) {
         AccessibilityNodeInfo nodeInfo = event.getSource();
         if (nodeInfo != null && MainActivity.flag) {
             int eventType = event.getEventType();
             if (eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED || eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
                 if (handleMap.get(event.getWindowId()) == null ) {
                     boolean handled = iterateNodesAndHandle(nodeInfo);
                     if (handled) {
                         handleMap.put(event.getWindowId(), true );
                     }
                 }
             }
 
         }
     }
 
     @Override
     public void onInterrupt() {
 
     }
 
     //遍历节点,模拟点击安装按钮
     private boolean iterateNodesAndHandle(AccessibilityNodeInfo nodeInfo) {
         if (nodeInfo != null ) {
             int childCount = nodeInfo.getChildCount();
             if ( "android.widget.Button" .equals(nodeInfo.getClassName())) {
                 String nodeCotent = nodeInfo.getText().toString();
                 Log.d(TAG, "content is: " + nodeCotent);
                 if ( "安装" .equals(nodeCotent) || "完成" .equals(nodeCotent) || "确定" .equals(nodeCotent)) {
                     nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                     return true ;
                 }
             }
             //遇到ScrollView的时候模拟滑动一下
             else if ( "android.widget.ScrollView" .equals(nodeInfo.getClassName())) {
                 nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
             }
             for ( int i = 0 ; i < childCount; i++) {
                 AccessibilityNodeInfo childNodeInfo = nodeInfo.getChild(i);
                 if (iterateNodesAndHandle(childNodeInfo)) {
                     return true ;
                 }
             }
         }
         return false ;
     }
}</integer,></code>

最后是配置文件AndroidManifest.xml:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<code class = "hljs xml" ><manifest package = "com.slientinstalltest" xmlns:android= "http://schemas.android.com/apk/res/android" >
 
     <uses-permission android:name= "android.permission.READ_EXTERNAL_STORAGE" >
 
     
         
             <intent-filter>
                 
 
                 <category android:name= "android.intent.category.LAUNCHER" >
             </category></action></intent-filter>
         </activity>
 
         <service android:label= "智能安装App" android:name= ".MyAccessibilityService" android:permission= "android.permission.BIND_ACCESSIBILITY_SERVICE" >
             <intent-filter>
                 
             </action></intent-filter>
             <meta-data android:name= "android.accessibilityservice" android:resource= "@xml/accessibility_service_config" >
         </meta-data></service>
     </application>
 
</uses-permission></manifest></code>

注意:请把自己要安装的apk放到sdcard上,并且修改代码中的apk路径和包名

9 运行效果

这里写图片描述


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值