Android輔助功能實(shí)現(xiàn)自動(dòng)搶紅包(附源碼)
一、描述
最近看到同事有用搶紅包的軟件,就想看看搶紅包的具體實(shí)現(xiàn)是如何的,所以了解了一下,有用輔助功能實(shí)現(xiàn)的,所以在下面的示例中會(huì)展示一個(gè)搶紅包的小Demo,附帶源碼搶紅包源碼。
二、效果圖

在桌面收到紅包進(jìn)行搶

在聊天頁面收到口令紅包
三、AccessibilityService使用
創(chuàng)建輔助服務(wù)類,繼承AccessibilityService,實(shí)現(xiàn)兩個(gè)接口,接收系統(tǒng)的事件
public class MyService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
}
@Override
public void onInterrupt() {
}
}
輔助服務(wù)的配置文件,配置事件,在 res/xml下創(chuàng)建accessibility_service_info.xml
//具體屬性的說明在第5點(diǎn)有說明 <?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/accessibility_service_description" android:accessibilityEventTypes="typeAllMask" android:accessibilityFeedbackType="feedbackGeneric" android:notificationTimeout="100" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" android:packageNames="top.cokernut.sample" android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity" />
注冊(cè)Service輔助服務(wù),并且為Service附加上第二步創(chuàng)建的xml,看清除下面的一些屬性,必須要加,如果有的沒加的話是沒效果的
<service
android:name=".MyService"
android:label="輔助功能"
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/accessibility_service_info" />
</service>
4 清單文件中添加權(quán)限
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
輔助服務(wù)配置文件xml屬性說明:
//是否可以檢索整個(gè)層級(jí)下的內(nèi)容 android:canRetrieveWindowContent="true"級(jí)下的信息 //事件通知觸發(fā)點(diǎn),比如窗口打開,滑動(dòng),焦點(diǎn)變化,長按等。 android:accessibilityEventTypes="typeAllMask" #TYPES_ALL_MASK:所有類型 #TYPE_VIEW_CLICKED :單擊 #TYPE_VIEW_LONG_CLICKED :長按 #TYPE_VIEW_SELECTED :選中 #TYPE_VIEW_FOCUSED :獲取焦點(diǎn) #TYPE_VIEW_TEXT_CHANGED :文字改變 #TYPE_WINDOW_STATE_CHANGED :窗口狀態(tài)改變 //表示反饋方式,比如是語音播放,還是震動(dòng) android:accessibilityFeedbackType="feedbackGeneric" //接受事件的時(shí)間間隔,通常將其設(shè)置為100即可. android:notificationTimeout="100" //表示該服務(wù)是用來單獨(dú)監(jiān)聽哪個(gè)應(yīng)用的產(chǎn)生的事件,其他的都會(huì)過濾,如果不填就是對(duì)所有的應(yīng)用進(jìn)行監(jiān)聽,填入包名即可。 android:packageNames="top.cokernut.sample" //在代碼中我們就可以通過node節(jié)點(diǎn)來getViewIdResourceName()獲取對(duì)應(yīng)的節(jié)點(diǎn)的id android:accessibilityFlags="flagDefault"
提供一個(gè)AccessibilityService的基類,集成了一些常用方法:
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當(dāng)前輔助服務(wù)是否啟用
*
* @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;
}
/**
* 前往開啟輔助服務(wù)界面
*/
public void goAccess() {
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
/**
* 模擬點(diǎn)擊事件
*
* @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);
}
/**
* 查找對(duì)應(yīng)文本的View
*
* @param text text
* @return View
*/
public AccessibilityNodeInfo findViewByText(String text) {
return findViewByText(text, false);
}
/**
* 查找對(duì)應(yīng)文本的View
*
* @param text text
* @param clickable 該View是否可以點(diǎn)擊
* @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;
}
/**
* 查找對(duì)應(yīng)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()) {
for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {
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) {
}
@Override
public void onInterrupt() {
}
}
四、QQ搶紅包
(一)搶紅包流程:
- 通知欄收到QQ的消息,發(fā)現(xiàn)是QQ紅包,模擬點(diǎn)擊消息進(jìn)入聊天頁面
- 檢索頁面上的所有元素,發(fā)現(xiàn)有包含“點(diǎn)擊拆開”的字眼,就模擬點(diǎn)擊打開紅包窗口
- 一兩秒后執(zhí)行Back操作,關(guān)閉紅包窗口。
- 繼續(xù)等待消息來到。
(二)實(shí)現(xiàn)功能:
- 鎖屏搶紅包(不可以有密碼或者圖案之類的鎖屏)
- 口令紅包,自動(dòng)輸入口令并且發(fā)送
- 搶完紅包后,自動(dòng)回復(fù)感謝語,可在紅包設(shè)置里自行設(shè)置內(nèi)容
- 其他的功能就沒繼續(xù)往下做了,知道方法,其他都可能慢慢研究出來。
(三)搶紅包輔助功能類,注釋都寫好了,很好理解,類中有用到QQConstant類,在第四點(diǎn)貼出了代碼
/**
* 描述:QQ搶紅包服務(wù)
* 作者:卜俊文
* 郵箱:344176791@qq.com
* 日期:2017/11/6 上午9:25
*/
public class EnvelopeService extends BaseAccessibilityService {
//鎖屏、解鎖相關(guān)
private KeyguardManager.KeyguardLock kl;
//喚醒屏幕相關(guān)
private PowerManager.WakeLock wl = null;
private long delayTime = 0;//延遲搶的時(shí)間
/**
* 描述:所有事件響應(yīng)的時(shí)候會(huì)回調(diào)
* 作者:卜俊文
* 郵箱:344176791@qq.com
* 日期:2017/11/6 上午9:26
*/
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
//驗(yàn)證搶紅包的開關(guān)
if (!invalidEnable()) {
return;
}
//事件類型
int eventType = event.getEventType();
//獲取包名
CharSequence packageName = event.getPackageName();
if (TextUtils.isEmpty(packageName)) {
return;
}
switch (eventType) {
//狀態(tài)欄變化
case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
if (QQConstant.QQ_PACKAGE_NAME.equals(packageName)) {
//處理狀態(tài)欄上QQ的消息,如果是紅包就跳轉(zhuǎn)過去
progressQQStatusBar(event);
}
break;
//窗口切換的時(shí)候回調(diào)
case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
if (QQConstant.QQ_PACKAGE_NAME.equals(packageName)) {
//處理正在QQ聊天窗口頁面,有其他群或者人有新的紅包提醒,跳轉(zhuǎn)過去。
progressNewMessage(event);
//處理聊天頁面的紅包
progressQQChat(event);
}
break;
}
}
/**
* 描述:處理新消息
* 作者:卜俊文
* 郵箱:344176791@qq.com
* 日期:2017/11/3 下午11:21
*/
private void progressNewMessage(AccessibilityEvent event) {
if (event == null) {
return;
}
AccessibilityNodeInfo source = event.getSource();
if (source == null) {
return;
}
//根據(jù)event的source里的text,來判斷這個(gè)消息是否包含[QQ紅包]的字眼,有的話就跳轉(zhuǎn)過去
CharSequence text = source.getText();
if (!TextUtils.isEmpty(text) && text.toString().contains(QQConstant.QQ_ENVELOPE_KEYWORD)) {
performViewClick(source);
}
}
/**
* 描述:驗(yàn)證搶紅包是否開啟
* 作者:卜俊文
* 郵箱:344176791@qq.com
* 日期:2017/11/3 下午4:57
*/
private boolean invalidEnable() {
return SettingConfig.getInstance().getReEnable();
}
/**
* 描述:處理QQ狀態(tài)欄
* 作者:卜俊文
* 郵箱:344176791@qq.com
* 日期:2017/11/1 下午1:49
*/
public void progressQQStatusBar(AccessibilityEvent event) {
List<CharSequence> text = event.getText();
//開始檢索界面上是否有QQ紅包的文本,并且他是通知欄的信息
if (text != null && text.size() > 0) {
for (CharSequence charSequence : text) {
if (charSequence.toString().contains(QQConstant.QQ_ENVELOPE_KEYWORD)) {
//說明存在紅包彈窗,馬上進(jìn)去
if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) {
Notification notification = (Notification) event.getParcelableData();
if (notification == null) {
return;
}
PendingIntent pendingIntent = notification.contentIntent;
if (pendingIntent == null) {
return;
}
try {
//要跳轉(zhuǎn)之前,先進(jìn)行解鎖屏幕,然后再跳轉(zhuǎn),有可能你現(xiàn)在屏幕是鎖屏狀態(tài),先進(jìn)行解鎖,然后打開頁面,有密碼的可能就不行了
wakeUpAndUnlock(MyApp.context);
//跳轉(zhuǎn)
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
}
}
}
}
}
/**
* 描述:處理QQ聊天紅包
* 作者:卜俊文
* 郵箱:344176791@qq.com
* 日期:2017/11/1 下午1:56
*/
public void progressQQChat(AccessibilityEvent event) {
if (TextUtils.isEmpty(event.getClassName())) {
return;
//如果當(dāng)前頁面是聊天頁面或者當(dāng)前的描述信息是"返回消息界面",就肯定是對(duì)話頁面
}
//驗(yàn)證當(dāng)前事件是否符合查詢頁面上的紅包
if (!invalidEnvelopeUi(event)) {
return;
}
//延遲點(diǎn)擊紅包,防止被檢測到開了搶紅包,不過感覺還是感覺會(huì)被檢測到,應(yīng)該有的效果吧...
try {
Thread.sleep(delayTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
//普通紅包,檢索點(diǎn)擊拆開的字眼。
List<AccessibilityNodeInfo> envelope = findViewListByText(QQConstant.QQ_CLICK_TAKE_APART, false);
//處理普通紅包
progressNormal(envelope);
//口令紅包,檢索口令紅包的字眼。
List<AccessibilityNodeInfo> passwordList = findViewListByText(QQConstant.QQ_CLICK_PASSWORD_DIALOG, false);
//處理口令紅包
progressPassword(passwordList);
}
/**
* 描述:驗(yàn)證是否現(xiàn)在是在聊天頁面,可以進(jìn)行搶紅包處理
* 作者:卜俊文
* 郵箱:344176791@qq.com
* 日期:2017/11/3 上午11:52
*
* @param event
*/
public boolean invalidEnvelopeUi(AccessibilityEvent event) {
//判斷類名是否是聊天頁面
if (!QQConstant.QQ_IM_CHAT_ACTIVITY.equals(event.getClassName().toString())) {
return true;
}
//判斷頁面中的元素是否有點(diǎn)擊拆開的文本,有就返回可以進(jìn)行查詢了
int recordCount = event.getRecordCount();
if (recordCount > 0) {
for (int i = 0; i < recordCount; i++) {
AccessibilityRecord record = event.getRecord(i);
if (record == null) {
break;
}
List<CharSequence> text = record.getText();
if (text != null && text.size() > 0 && text.contains(QQConstant.QQ_CLICK_TAKE_APART)) {
//如果文本中有點(diǎn)擊拆開的字眼,就返回可以進(jìn)行查詢了
return true;
}
}
}
return false;
}
/**
* 回到系統(tǒng)桌面
*/
private void back2Home(int time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
Intent home = new Intent(Intent.ACTION_MAIN);
home.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
home.addCategory(Intent.CATEGORY_HOME);
startActivity(home);
}
/**
* 描述:處理普通紅包
* 作者:卜俊文
* 郵箱:344176791@qq.com
* 日期:2017/11/1 下午5:02
*/
public void progressNormal(List<AccessibilityNodeInfo> passwordList) {
if (passwordList != null && passwordList.size() > 0) {
for (AccessibilityNodeInfo accessibilityNodeInfo : passwordList) {
if (accessibilityNodeInfo != null && !TextUtils.isEmpty(accessibilityNodeInfo.getText()) && QQConstant.QQ_CLICK_TAKE_APART.equals(accessibilityNodeInfo.getText().toString())) {
//點(diǎn)擊拆開紅包
performViewClick(accessibilityNodeInfo);
//回復(fù)感謝信息,根據(jù)配置文件中配置的回復(fù)信息回復(fù)
String reReplyMessage = SettingConfig.getInstance().getReReplyMessage();
if (!TextUtils.isEmpty(reReplyMessage)) {
replyMessage(reReplyMessage);
}
}
}
//最后延遲事件觸發(fā)返回事件,關(guān)閉紅包頁面
performBackClick(1200);
}
}
/**
* 描述:處理口令紅包
* 作者:卜俊文
* 郵箱:344176791@qq.com
* 日期:2017/11/1 下午4:58
*
* @param passwordList
*/
public void progressPassword(List<AccessibilityNodeInfo> passwordList) {
if (passwordList != null && passwordList.size() > 0) {
for (AccessibilityNodeInfo accessibilityNodeInfo : passwordList) {
if (accessibilityNodeInfo != null && !TextUtils.isEmpty(accessibilityNodeInfo.getText()) && QQConstant.QQ_CLICK_PASSWORD_DIALOG.equals(accessibilityNodeInfo.getText().toString())) {
//如果口令紅包存在,就在輸入框中進(jìn)行輸入,然后發(fā)送
AccessibilityNodeInfo parent = accessibilityNodeInfo.getParent();
if (parent != null) {
CharSequence contentDescription = parent.getContentDescription();
if (!TextUtils.isEmpty(contentDescription)) {
//1. 獲取口令
String key = (String) contentDescription;
if (key.contains(",") && key.contains("口令:")) {
key = key.substring(key.indexOf("口令:") + 3, key.lastIndexOf(","));
}
Log.e("口令", key);
//2. 填寫口令到編輯框上然后進(jìn)行發(fā)送
replyMessage(key);
//返回,關(guān)閉紅包頁面
performBackClick(1200);
}
}
}
}
}
}
/**
* 喚醒屏幕并解鎖權(quán)限
* <uses-permission android:name="android.permission.WAKE_LOCK" />
*/
@SuppressLint("Wakelock")
@SuppressWarnings("deprecation")
public void wakeUpAndUnlock(Context context) {
// 點(diǎn)亮屏幕
wl.acquire();
// 釋放
wl.release();
// 解鎖
kl.disableKeyguard();
}
/**
* 描述:回復(fù)消息,無延遲
* 作者:卜俊文
* 郵箱:344176791@qq.com
* 日期:2017/11/3 下午5:10
*/
public void replyMessage(String key) {
replyMessage(key, 0);
}
/**
* 描述:回復(fù)消息
* 作者:卜俊文
* 郵箱:344176791@qq.com
* 日期:2017/11/3 下午5:10
*/
public void replyMessage(String key, int time) {
//延遲
if (time > 0) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//獲取QQ聊天頁面輸入框
AccessibilityNodeInfo chat_edit = findViewByID(QQConstant.QQ_CHAT_MESSAGE_INPUT);
if (chat_edit != null) {
//把口令粘貼到輸入框中
pastaText(chat_edit, MyApp.context, key);
//獲取QQ聊天頁面發(fā)送消息按鈕
AccessibilityNodeInfo sendMessage = findViewByID(QQConstant.QQ_CHAT_MESSAGE_SEND);
//然后就按下發(fā)送按鈕
if (sendMessage != null && Button.class.getName().equals(sendMessage.getClassName())) {
performViewClick(sendMessage);
}
}
}
@Override
public void onInterrupt() {
}
@Override
protected void onServiceConnected() {
super.onServiceConnected();
// 獲取電源管理器對(duì)象
PowerManager pm = (PowerManager) MyApp.context
.getSystemService(Context.POWER_SERVICE);
// 獲取PowerManager.WakeLock對(duì)象,后面的參數(shù)|表示同時(shí)傳入兩個(gè)值,最后的是調(diào)試用的Tag
wl = pm.newWakeLock(
PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright");
KeyguardManager km = (KeyguardManager) MyApp.context.getSystemService(Context.KEYGUARD_SERVICE);
kl = km.newKeyguardLock("unLock");
//初始化屏幕的監(jiān)聽
ScreenListener screenListener = new ScreenListener(MyApp.context);
screenListener.begin(new ScreenListener.ScreenStateListener() {
@Override
public void onScreenOn() {
Log.e("ScreenListener", "屏幕打開了");
}
@Override
public void onScreenOff() {
//在屏幕關(guān)閉的時(shí)候,進(jìn)行鎖屏,不執(zhí)行的話,鎖屏就失效了,因?yàn)橐獙?shí)現(xiàn)鎖屏狀態(tài)下也可以進(jìn)行搶紅包。
Log.e("ScreenListener", "屏幕關(guān)閉了");
if (kl != null) {
kl.disableKeyguard();
kl.reenableKeyguard();
}
}
@Override
public void onUserPresent() {
Log.e("ScreenListener", "解鎖了");
}
});
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
(四)QQ輔助服務(wù)里有用到的常量
public class QQConstant {
//QQ的應(yīng)用包名
public static final String QQ_PACKAGE_NAME = "com.tencent.mobileqq";
//狀態(tài)欄紅包關(guān)鍵字
public static final String QQ_ENVELOPE_KEYWORD = "[QQ紅包]";
//QQ聊天頁面
public static final String QQ_IM_CHAT_ACTIVITY = "com.tencent.mobileqq.activity.SplashActivity";
//點(diǎn)擊拆開
public static final String QQ_CLICK_TAKE_APART = "點(diǎn)擊拆開";
//口令紅包
public static final String QQ_CLICK_PASSWORD_DIALOG = "口令紅包";
//聊天頁面,輸入框ID
public static final String QQ_CHAT_MESSAGE_INPUT = "com.tencent.mobileqq:id/input";
//聊天頁面,發(fā)送按鈕
public static final String QQ_CHAT_MESSAGE_SEND = "com.tencent.mobileqq:id/fun_btn";
}
五、紅包問題
用的時(shí)候偶爾會(huì)被QQ檢測到用了紅包插件,可能是因?yàn)閾尩乃俣忍?,?dǎo)致數(shù)據(jù)不符合正常的點(diǎn)擊時(shí)間,我有加入一個(gè)延遲時(shí)間,不知道有沒有效果,如果有知道的也可以留言,謝謝。
在QQ的主頁面上,收到消息的時(shí)候通知欄是不會(huì)通知的,所以這里不能進(jìn)行解析通知欄跳轉(zhuǎn)聊天頁面,沒有找到什么元素可以告訴我怎么進(jìn)入紅包的聊天頁面,如果有知道的可以留言,謝謝。
這種輔助服務(wù)的方式搶紅包,進(jìn)入聊天頁面后,他檢索字段只會(huì)檢索當(dāng)前頁面可視的元素,某些紅包要是在聊天記錄上面看不見的,需要滑動(dòng)上去才可以觸發(fā)解析紅包,不過一般不會(huì)一次性10個(gè)紅包都發(fā)出來吧,嘿嘿。
六、總結(jié)
學(xué)習(xí)制作了這個(gè)項(xiàng)目,也了解了輔助功能的使用,感覺這個(gè)還是可以做很多東西的,上面已經(jīng)貼出了核心代碼,要源碼的可以點(diǎn)擊。搶紅包源碼
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 教你一步步實(shí)現(xiàn)Android微信自動(dòng)搶紅包
- Android輔助功能AccessibilityService與搶紅包輔助
- Android實(shí)現(xiàn)QQ搶紅包插件
- Android中微信搶紅包插件原理解析及開發(fā)思路
- Android搶紅包插件實(shí)現(xiàn)原理淺析
- Android實(shí)現(xiàn)紅包雨動(dòng)畫效果
- 分享Android微信紅包插件
- Android實(shí)現(xiàn)微信自動(dòng)搶紅包的程序
- Android微信自動(dòng)搶紅包插件優(yōu)化和實(shí)現(xiàn)
- SurfaceView實(shí)現(xiàn)紅包雨平移動(dòng)畫
相關(guān)文章
Android實(shí)現(xiàn)為GridView添加邊框效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)為GridView添加邊框效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
Android開發(fā)實(shí)現(xiàn)拍照功能的方法實(shí)例解析
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)拍照功能的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android拍照功能的具體實(shí)現(xiàn)步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-10-10
Android開發(fā)實(shí)現(xiàn)的標(biāo)準(zhǔn)體重計(jì)算器功能示例
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)的標(biāo)準(zhǔn)體重計(jì)算器功能,結(jié)合實(shí)例形式分析了Android體重計(jì)算器的界面布局與功能實(shí)現(xiàn)相關(guān)操作技巧,需要的朋友可以參考下2017-12-12
Android實(shí)現(xiàn)APP環(huán)境分離(利用Gradle)
有過互聯(lián)網(wǎng)軟件開發(fā)經(jīng)驗(yàn)的朋友一定對(duì)于測試環(huán)境和生產(chǎn)環(huán)境這兩個(gè)詞很是熟悉,在開發(fā)和測試階段,我們常常需要在同一個(gè)設(shè)備上同時(shí)安裝著兩套甚至多套環(huán)境的同一個(gè)應(yīng)用,便于觀察調(diào)試。所以這篇文章就來和大家分享Android利用Gradle實(shí)現(xiàn)APP環(huán)境分離的方法。2016-09-09
Android應(yīng)用借助LinearLayout實(shí)現(xiàn)垂直水平居中布局
這篇文章主要介紹了Android應(yīng)用借助LinearLayout實(shí)現(xiàn)垂直水平居中布局的方法,文中列舉了LinearLayout線性布局下居中相關(guān)的幾個(gè)重要參數(shù),需要的朋友可以參考下2016-04-04
android實(shí)現(xiàn)搜索功能并將搜索結(jié)果保存到SQLite中(實(shí)例代碼)
這篇文章主要介紹了android實(shí)現(xiàn)搜索功能并將搜索結(jié)果保存到SQLite中,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04

