用实例来熟悉AccessibilityService
实现自动安装程序
1.注册服务 在mainfests中加入
<service
android:name=".AutoInstallAccessibilityService"
android:exported="true"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/install"/>
</service>
2.android7.0 读取文件要加入以下代码
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.android7.fileprovider"
android:grantUriPermissions="true"
android:exported="false"
>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
3.上边两个要用到的resource文件install和file_paths 还需要加入 accessibility.xml文件
accessibility.xml
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:description="@string/demo"
android:accessibilityFeedbackType="feedbackSpoken"
android:canRetrieveWindowContent="true"
android:notificationTimeout="1000"/>
install.xml
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:description="@string/install"
android:accessibilityFeedbackType="feedbackSpoken"
android:canRetrieveWindowContent="true"
android:notificationTimeout="1000"/>
file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path path="Android/data/com.ld.taptest/" name="files_root" />
<external-path path="." name="external_storage_root" />
<root-path
name="root_path"
path="sdcard" />
<root-path name="root" path="" />
<files-path name="files" path="." />
<cache-path name="cache" path="." />
<external-path name="external" path="." />
<external-files-path name="name" path="path" />
<external-cache-path name="name" path="path" />
</paths>
4.需要的基础文件BaseAccessibilityService.java
public class BaseAccessibilityService extends AccessibilityService {
private AccessibilityManager mAccessibilityManager;
private Context mContext;
private static BaseAccessibilityService mInstance;
public void init(Context context) {
mContext = context.getApplicationContext();
mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
}
public static BaseAccessibilityService getInstance() {
if (mInstance == null) {
mInstance = new BaseAccessibilityService();
}
return mInstance;
}
/**
* Check当前辅助服务是否启用
*
* @param serviceName serviceName
* @return 是否启用
*/
private boolean checkAccessibilityEnabled(String serviceName) {
List<AccessibilityServiceInfo> accessibilityServices =
mAccessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC);
for (AccessibilityServiceInfo info : accessibilityServices) {
if (info.getId().equals(serviceName)) {
return true;
}
}
return false;
}
/**
* 前往开启辅助服务界面
*/
public void goAccess() {
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
/**
* 模拟点击事件
*
* @param nodeInfo nodeInfo
*/
public void performViewClick(AccessibilityNodeInfo nodeInfo) {
if (nodeInfo == null) {
return;
}
while (nodeInfo != null) {
if (nodeInfo.isClickable()) {
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
break;
}
nodeInfo = nodeInfo.getParent();
}
}
/**
* 模拟返回操作
*/
public void performBackClick() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
performGlobalAction(GLOBAL_ACTION_BACK);
}
/**
* 模拟下滑操作
*/
public void performScrollBackward() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
performGlobalAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
}
/**
* 模拟上滑操作
*/
public void performScrollForward() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
performGlobalAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
}
/**
* 查找对应文本的View
*
* @param text text
* @return View
*/
public AccessibilityNodeInfo findViewByText(String text) {
return findViewByText(text, false);
}
/**
* 查找对应文本的View
*
* @param text text
* @param clickable 该View是否可以点击
* @return View
*/
public AccessibilityNodeInfo findViewByText(String text, boolean clickable) {
AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();
if (accessibilityNodeInfo == null) {
return null;
}
List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByText(text);
if (nodeInfoList != null && !nodeInfoList.isEmpty()) {
for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {
if (nodeInfo != null && (nodeInfo.isClickable() == clickable)) {
return nodeInfo;
}
}
}
return null;
}
/**
* 查找对应ID的View
*
* @param id id
* @return View
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public AccessibilityNodeInfo findViewByID(String id) {
AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();
if (accessibilityNodeInfo == null) {
return null;
}
List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(id);
if (nodeInfoList != null && !nodeInfoList.isEmpty()) {
Log.d("dd", "findViewByID: "+nodeInfoList.size());
for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {
Log.d("dd", "findViewByID: "+nodeInfo.toString());
if (nodeInfo != null) {
return nodeInfo;
}
}
}
return null;
}
public void clickTextViewByText(String text) {
AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();
if (accessibilityNodeInfo == null) {
return;
}
List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByText(text);
if (nodeInfoList != null && !nodeInfoList.isEmpty()) {
for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {
if (nodeInfo != null) {
performViewClick(nodeInfo);
break;
}
}
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public void clickTextViewByID(String id) {
AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();
if (accessibilityNodeInfo == null) {
return;
}
List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(id);
if (nodeInfoList != null && !nodeInfoList.isEmpty()) {
for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {
if (nodeInfo != null) {
performViewClick(nodeInfo);
break;
}
}
}
}
/**
* 模拟输入
*
* @param nodeInfo nodeInfo
* @param text text
*/
public void inputText(AccessibilityNodeInfo nodeInfo, String text) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Bundle arguments = new Bundle();
arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("label", text);
clipboard.setPrimaryClip(clip);
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_FOCUS);
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_PASTE);
}
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.d("dd", "onAccessibilityEvent: "+event.toString());
}
@Override
public void onInterrupt() {
}
}
5.监听安装界面AutoInstallAccessibilityService.java
public class AutoInstallAccessibilityService extends BaseAccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
super.onAccessibilityEvent(event);
// && event.getPackageName().equals("com.miui.packageinstaller")
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED ) {
AccessibilityNodeInfo nodeInfo = findViewByText("安装", true);
if (nodeInfo != null) {
performViewClick(nodeInfo);
}
}
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
||event.getEventType() == AccessibilityEvent. TYPE_WINDOW_CONTENT_CHANGED) {
AccessibilityNodeInfo nodeInfo = findViewByText("完成", true);
if (nodeInfo != null) {
performViewClick(nodeInfo);
}
}
}
}
6.mainactivity代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button button_install;
private Button button_open;
private Context mContext;
private String[] PERMISSION_CAMERA={Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化服务
BaseAccessibilityService.getInstance().init(this);
mContext=this;
initview();
initdata();
}
private void initview() {
button_install=findViewById(R.id.button);
button_open=findViewById(R.id.button_open);
button_open.setOnClickListener(this);
button_install.setOnClickListener(this);
PermissionUtils.checkAndRequestMorePermissions(mContext, PERMISSION_CAMERA, 0, new PermissionUtils.PermissionRequestSuccessCallBack() {
@Override
public void onHasPermission() {
Toast.makeText(mContext,"授权成功!",Toast.LENGTH_SHORT).show();
}
});
}
private void initdata() {
}
@Override
public void onClick(View v) {
switch (v.getId())
{
case R.id.button:
checkservice();
install();
break;
case R.id.button_open:
openserver();
break;
}
}
private void checkservice() {
if (isAccessibilitySettingsOn(this))
Toast.makeText(this,"已经有权限了",Toast.LENGTH_LONG).show();
else
Toast.makeText(this,"没有权限",Toast.LENGTH_LONG).show();
}
private void openserver() {
BaseAccessibilityService.getInstance().goAccess();
}
private void install() {
installApk();
}
public void installApk() {
File file = new File(Environment.getExternalStorageDirectory(),
"test.apk");
Log.d("dd", "installApk: "+file.exists()+" size:"+file.length());
Intent intent = new Intent(Intent.ACTION_VIEW);
// 仅需改变这一行
FileProvider7.setIntentDataAndType(this,
intent, "application/vnd.android.package-archive", file, true);
startActivity(intent);
}
/**
* 显示前往应用设置Dialog
*
*/
private void showToAppSettingDialog() {
new AlertDialog.Builder(mContext)
.setTitle("需要权限")
.setMessage("我们需要相关权限,才能实现功能,点击前往,将转到应用的设置界面,请开启应用的相关权限。")
.setPositiveButton("前往", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
PermissionUtils.toAppSetting(mContext);
}
})
.setNegativeButton("取消", null).show();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1:
// if(PermissionUtils.isPermissionRequestSuccess(grantResults))
// {
// // 权限申请成功
// //toCamera();
// } else {
// Toast.makeText(mContext,"打开相机失败",Toast.LENGTH_SHORT).show();
// }
break;
case 0:
PermissionUtils.onRequestMorePermissionsResult(mContext, PERMISSION_CAMERA, new PermissionUtils.PermissionCheckCallBack() {
@Override
public void onHasPermission() {
Toast.makeText(mContext,"授权成功!",Toast.LENGTH_SHORT).show();
}
@Override
public void onUserHasAlreadyTurnedDown(String... permission) {
Toast.makeText(mContext, "我们需要"+ Arrays.toString(permission)+"权限", Toast.LENGTH_SHORT).show();
}
@Override
public void onUserHasAlreadyTurnedDownAndDontAsk(String... permission) {
Toast.makeText(mContext, "我们需要"+ Arrays.toString(permission)+"权限", Toast.LENGTH_SHORT).show();
showToAppSettingDialog();
}
});
}
}
// 判断辅助服务是否开启
private boolean isAccessibilitySettingsOn(Context mContext) {
int accessibilityEnabled = 0;
final String service = getPackageName() + "/" + AutoInstallAccessibilityService.class.getCanonicalName();
try {
accessibilityEnabled = Settings.Secure.getInt(
mContext.getApplicationContext().getContentResolver(),
android.provider.Settings.Secure.ACCESSIBILITY_ENABLED);
Log.v(TAG, "accessibilityEnabled = " + accessibilityEnabled);
} catch (Settings.SettingNotFoundException e) {
Log.e(TAG, "Error finding setting, default accessibility to not found: "
+ e.getMessage());
}
TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');
if (accessibilityEnabled == 1) {
Log.v(TAG, "***ACCESSIBILITY IS ENABLED*** -----------------");
String settingValue = Settings.Secure.getString(
mContext.getApplicationContext().getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (settingValue != null) {
mStringColonSplitter.setString(settingValue);
while (mStringColonSplitter.hasNext()) {
String accessibilityService = mStringColonSplitter.next();
Log.v(TAG, "-------------- > accessibilityService :: " + accessibilityService + " " + service);
if (accessibilityService.equalsIgnoreCase(service)) {
Log.v(TAG, "We've found the correct setting - accessibility is switched on!");
return true;
}
}
}
} else {
Log.v(TAG, "***ACCESSIBILITY IS DISABLED***");
}
return false;
}
}
7.里面有6.0以上申请权限的代码没有贴出来,如果不授予读写权限会出现安装包损坏的提示
8.运行界面展示,比较模糊
9.完成