您的位置:首页 > 移动开发 > Android开发

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

2016-01-22 19:43 441 查看
上一篇博客里面介绍了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"/>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: