Android利用AccessibilityService实现自动装总结(二)

上一篇博客里面介绍了AccessibilityService的用法http://blog.csdn.net/u014310722/article/details/50563160

下面我们主要来介绍一下利用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"/>





评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值