Android利用AccessibilityService实现自动装总结(二)
2016-01-22 19:43
441 查看
上一篇博客里面介绍了AccessibilityService的用法http://blog.csdn.net/u014310722/article/details/50563160
下面我们主要来介绍一下利用AccessibilityService实现自动安装的功能:
MainActivity的主要代码:
下载完成的监听事件,因为DownloadManager下载完成后,会自动发一个广播,所以我们只要监听该广播的状态就行了:主要代码如下
一:在自动安装的服务开启后,你通过别的路径路径下载的apk文件,点击安装的时候也会自动安装。
原因:AutomaticInstallationService监听的包名是全系统的,他无法判断你是不是在本应用汇总安装
解决办法:在SharedPrefrence里面存储一个boolean型变量,如果是从本应用中进入安装界面时,则赋值true,安装完成后赋值false,其他地方进入赋值false,安装的时候,读取该值,如果为true,则自动安装,否则不自动安装
二:在AutomaticInstallationService类中,重写onAccessibilityEvent(AccessibilityEvent event)时,event.getSource()一直返回为空
原因:没有配置AutomaticInstallationService的canRetrieveWindowContent属性:
解决方法:在配置AutomaticInstallationService的xml文件中,增加该属性,并设置为true:
下面我们主要来介绍一下利用AccessibilityService实现自动安装的功能:
MainActivity的主要代码:
public class MainActivity extends Activity { /** * 下载文件的button */ private Button mDownLoadFileBtn; /** * 广播接收者 */ private DownloadFileCompleteReceiver mDownloadFileCompleteReceiver; /** * 获取安装包信息 */ private PackageInfo mPackageInfo; /** * 判断是否安装了魔秀主题,true表示安装 */ private boolean isThemeIntalled = false; /** * 用来显示悬浮窗的service */ private Intent service; // 用来判断是否从设置页面返回 private final int INTENT_TO_SETTING = 0; private SharedPreferences mSharedPreferences; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViews(); initOnListener(); } @Override protected void onResume() { super.onResume(); initBtnText(); } /** * 初始化下载按钮显示的字体,如果安装了魔秀主题则显示打开魔秀主题,则显示打开魔秀主题,否则显示下载文件 */ private void initBtnText() { try { mPackageInfo = this.getPackageManager().getPackageInfo( "com.moxiu.launcher", 0); } catch (NameNotFoundException e) { mPackageInfo = null; e.printStackTrace(); } if (mPackageInfo == null) { isThemeIntalled = false; mDownLoadFileBtn.setText(getString(R.string.download_file)); } else { isThemeIntalled = true; mDownLoadFileBtn.setText(getString(R.string.open_theme)); } } /** * 通过ID得到控件 * */ private void findViews() { mDownLoadFileBtn = (Button) findViewById(R.id.btn_download); } /** * 设置监听事件 */ private void initOnListener() { // 引导用户打开辅助功能 // 下载按钮的监听事件 mDownLoadFileBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (isThemeIntalled) { OpenOtherApp.openApp(MainActivity.this, "com.moxiu.launcher");// 根据包名打开魔秀主题 } else { downLoadFile(); } } }); } @Override protected void onDestroy() { super.onDestroy(); if (mDownloadFileCompleteReceiver != null) { unregisterReceiver(mDownloadFileCompleteReceiver); } } /** * 下载文件 */ private void downLoadFile() { DownloadFile.downloadFile(MainActivity.this, "http://a1.33lc.com:801/small/moxiuzhuomian_33lc.apk", "mxtheme"); } }下载文件的主要代码:
public class DownloadFile { public static void downloadFile(Context context, String fileUrl, String saveFilePath) { File file = new File(Environment.getExternalStorageDirectory() + "/" + saveFilePath + "/mxtheme.apk"); if (!file.exists()) { try { file.getParentFile().mkdirs(); } catch (SecurityException se) { se.printStackTrace(); } } else{ file.delete(); } DownloadManager.Request request = new DownloadManager.Request(Uri.parse(fileUrl)); request.setAllowedNetworkTypes(Request.NETWORK_WIFI); request.setNotificationVisibility(Request.VISIBILITY_VISIBLE); request.setTitle(context.getString(R.string.download_file)); request.setDescription(context.getString(R.string.download_mxtheme)); request.setAllowedOverRoaming(false); // 设置文件存放目录 request.setDestinationUri(Uri.fromFile(file)); DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); downloadManager.enqueue(request); } }
下载完成的监听事件,因为DownloadManager下载完成后,会自动发一个广播,所以我们只要监听该广播的状态就行了:主要代码如下
public class DownloadFileCompleteReceiver extends BroadcastReceiver { private final static String FILE_PATH = Environment.getExternalStorageDirectory() + "/mxtheme/mxtheme.apk"; private SharedPreferences mSharedPreferences; private Editor mEditor; @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) { Toast.makeText(context, context.getString(R.string.download_completed), Toast.LENGTH_SHORT).show(); //下载完成将自动安装设置成true,为的是区分我们自己下载的app和其它出处的app mSharedPreferences = context.getSharedPreferences( MxAutomaticinstallation.APP_NAME, Context.MODE_PRIVATE); mEditor = mSharedPreferences.edit(); mEditor.putBoolean(MxAutomaticinstallation.IS_AUTO_INSTALL, true); mEditor.commit(); // 调用安装器去安装我们的apk 一键安装开始啦,如果用户把那个服务打开了的话。 File file = new File(FILE_PATH); Intent intentInstall = new Intent(android.content.Intent.ACTION_VIEW); intentInstall.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); intentInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intentInstall); } } }AutomaticInstallationService类的主要代码:
public class AutomaticInstallationService extends AccessibilityService { // 大多数的手机包名一样,联想部分机型的手机不一样 private String[] packageNames = { "com.android.packageinstaller", "com.lenovo.security", "com.lenovo.safecenter" }; // 偏好设置文件,用来存取服务是否开启 private SharedPreferences mSharedPreferences; private Editor mEditor; /** * 此方法是accessibility service的配置信息 写在java类中是为了向下兼容 */ @Override protected void onServiceConnected() { super.onServiceConnected(); AccessibilityServiceInfo mAccessibilityServiceInfo = new AccessibilityServiceInfo(); // 响应事件的类型,这里是全部的响应事件(长按,单击,滑动等) mAccessibilityServiceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK; // 反馈给用户的类型,这里是语音提示 mAccessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN; // 过滤的包名 mAccessibilityServiceInfo.packageNames = packageNames; // 开启服务后,在偏好设置文件中将"isAllowAutoInstallation"的值设为true mSharedPreferences = getSharedPreferences(MxAutomaticinstallation.APP_NAME, Context.MODE_PRIVATE); mEditor = mSharedPreferences.edit(); mEditor.putBoolean(MxAutomaticinstallation.IS_ALLOW_AUTO_INSTALLATION, true); mEditor.commit(); setServiceInfo(mAccessibilityServiceInfo); } @Override public boolean onUnbind(Intent intent) { // 服务断开后,在偏好设置文件中将"isAllowAutoInstallation"的值设为false mSharedPreferences = getSharedPreferences(MxAutomaticinstallation.APP_NAME, Context.MODE_PRIVATE); mEditor = mSharedPreferences.edit(); mEditor.putBoolean(MxAutomaticinstallation.IS_ALLOW_AUTO_INSTALLATION, false); mEditor.commit(); return super.onUnbind(intent); } @Override public void onAccessibilityEvent(AccessibilityEvent event) { installApplication(event); } @Override public void onInterrupt() { } /** * 查找关键字并执行点击按钮的操作 * * @param event */ @SuppressLint("NewApi") private void installApplication(AccessibilityEvent event) { mSharedPreferences = getSharedPreferences(MxAutomaticinstallation.APP_NAME, Context.MODE_PRIVATE); boolean isAutoInstall = mSharedPreferences.getBoolean(MxAutomaticinstallation.IS_AUTO_INSTALL, false); // 若是true,是我们自己下载的app,可以执行自动安装,否则为普通安装 if (isAutoInstall == true) { if (event.getSource() != null && isContainInPackages(event.getPackageName().toString())) { // 得到“下一步”节点 findNodesByText(event, "下一步"); // 得到“安装”节点 findNodesByText(event, "安装"); // 得到“完成”节点 findNodesByText(event, "完成"); // 得到“打开”节点 findNodesByText(event, "打开"); } } } /** * 根据文字寻找节点 * * @param event * @param text * 文字 */ @SuppressLint("NewApi") private void findNodesByText(AccessibilityEvent event, String text) { List<AccessibilityNodeInfo> nodes = event.getSource().findAccessibilityNodeInfosByText(text); if (nodes != null && !nodes.isEmpty()) { for (AccessibilityNodeInfo info : nodes) { if (info.isClickable()) {// 只有根据节点信息是下一步,安装,完成,打开,且是可以点击的时候,才执行后面的点击操作 if (text.equals("完成") || text.equals("打开")) { // 如果安装完成,点击任意一个按钮把允许自动装的值改为false mSharedPreferences = getSharedPreferences(MxAutomaticinstallation.APP_NAME, Context.MODE_PRIVATE); mEditor = mSharedPreferences.edit(); mEditor.putBoolean(MxAutomaticinstallation.IS_AUTO_INSTALL, false); mEditor.commit(); File file = new File(Environment.getExternalStorageDirectory() + "/mxtheme/mxtheme.apk"); if (file.exists()) { file.delete(); } } else { info.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } } } } /** * 判断包名 * * @param str * 当前界面包名 * @return */ private boolean isContainInPackages(String str) { boolean flag = false; for (int i = 0; i < packageNames.length; i++) { if ((packageNames[i]).equals(str)) { flag = true; return flag; } } return flag; } }在完成这个功能的过程中,自己也遇到一些问题:解决方法如下:
一:在自动安装的服务开启后,你通过别的路径路径下载的apk文件,点击安装的时候也会自动安装。
原因:AutomaticInstallationService监听的包名是全系统的,他无法判断你是不是在本应用汇总安装
解决办法:在SharedPrefrence里面存储一个boolean型变量,如果是从本应用中进入安装界面时,则赋值true,安装完成后赋值false,其他地方进入赋值false,安装的时候,读取该值,如果为true,则自动安装,否则不自动安装
二:在AutomaticInstallationService类中,重写onAccessibilityEvent(AccessibilityEvent event)时,event.getSource()一直返回为空
原因:没有配置AutomaticInstallationService的canRetrieveWindowContent属性:
解决方法:在配置AutomaticInstallationService的xml文件中,增加该属性,并设置为true:
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:canRetrieveWindowContent="true" android:description="@string/description" android:notificationTimeout="100"/>
相关文章推荐
- 面向对象的六大原则(二)-- 开闭原则(切合Android,ImageLoader)
- Android增强的LinearLayout,带分隔线
- Android_YouthArea之ApeendTextView
- 从Android访问PC端的port (reverse port forwarding)
- Android学习历程11-SharedPreferences介绍
- Android应用Design Support Library完全使用实例
- 分享
- android notifyForDescendents 为false 的含义
- android Xutils 数据库操作源码分析
- Android Activity 之 重新创建
- Android Support 包一探究竟
- Android捕获程序异常退出时的错误log信息
- Android 防内存泄露的AsyncTask--WeakAsyncTask
- android 常用包
- 启动模式影响android操作
- android基础--tools:context=".MainActivity"作用
- Androidx学习笔记(17)-- 数据存储之XML
- Android自定义音量条控件
- Android的Activity之间传对象的方法
- 【Android】实现新闻分类(二级下拉菜单)效果