内容简介:目前主流的抢票软件是安装在浏览器上的插件,像猎豹、360浏览器等,用于在12306网站上抢票。常规情况下,使用12306网站订票时,如果刷新页面就需要再次填写个人信息,这就耽误了不少时间。这一耽误,可能需要“秒杀”的热门火车票就已经落入他人之手,而查看剩余车票时也需要在计算机前不断地点击刷新页面。
一、抢火车票
1、抢火车票软件的技术原理
目前主流的抢票软件是安装在浏览器上的插件,像猎豹、360浏览器等,用于在12306网站上抢票。
常规情况下,使用12306网站订票时,如果刷新页面就需要再次填写个人信息,这就耽误了不少时间。这一耽误,可能需要“秒杀”的热门火车票就已经落入他人之手,而查看剩余车票时也需要在计算机前不断地点击刷新页面。
人工操作效率远不如刷票软件
而抢票软件能够记录个人信息,自动重复登录,直到登录成功,代替缓慢的人工操作。并通过对12306网站的不断刷新和监控,一旦有人退票,抢票软件能立即发现。此外,部分软件从查询到下单可以直接勾选,不需再填写任何信息。有了这些便利功能,抢票软件确实可以将抢票成功率大大提高。
2、教大家一个自动抢票技术脚本
1)先准备好工具:
- 12306网站用户名和密码
- chrome浏览器及下载chromedriver
- Python代码
代码用的Python+Splinter开发,Splinter是一个使用 Python 开发的开源Web应用测试工具,它可以帮你实现自动浏览站点和与其进行交互。
Splinter执行的时候会自动打开你指定的浏览器,访问指定的URL。然后你所开发的模拟的任何行为,都会自动完成,你只需要坐在电脑面前,像看电影一样看着屏幕上各种动作自动完成然后收集结果即可。
2)基本实现原理:
找到相应URL,找到控件模拟登录、查询、订票操作。关键是找到控件名称,难点是起始地不是直接输入的页面值,需要在cookie中查出。
- 12306查询URL: https://kyfw.12306.cn/otn/leftTicket/init
- 12306登录URL: https://kyfw.12306.cn/otn/login/init
- 我的12306URL: https://kyfw.12306.cn/otn/index/initMy12306
- 购票确认URL: https://kyfw.12306.cn/otn/confirmPassenger/initDc
Python代码打开URL,找到控件填充值:
def login(self): self.driver.visit(self.login_url) # 填充用户名 self.driver.fill("loginUserDTO.user_name", self.username) # 填充密码 self.driver.fill("userDTO.password", self.passwd) print u"等待验证码,自行输入..."
找到用户名密码控件名
找到起始地控件名 :
确定起始地的值,方法Chrome浏览器中的“检查”功能(按F12),Network ---> Cookies中找到:
cookie中起始地的值
拷贝起始地的cookie值,我把几个常用的城市拷出来,放到了字典中:
cities= {'成都':'%u6210%u90FD%2CCDW', '重庆':'%u91CD%u5E86%2CCQW', '北京':'%u5317%u4EAC%2CBJP', '广州':'%u5E7F%u5DDE%2CGZQ', '杭州':'%u676D%u5DDE%2CHZH', '宜昌':'%u5B9C%u660C%2CYCN', '郑州':'%u90D1%u5DDE%2CZZF', '深圳':'%u6DF1%u5733%2CSZQ', '西安':'%u897F%u5B89%2CXAY', '大连':'%u5927%u8FDE%2CDLT', '武汉':'%u6B66%u6C49%2CWHN', '上海':'%u4E0A%u6D77%2CSHH', '南京':'%u5357%u4EAC%2CNJH', '合肥':'%u5408%u80A5%2CHFH'}
查询车票代码:
print u"购票页面开始..."
# 加载查询信息
self.driver.cookies.add({"_jc_save_fromStation": self.starts}) self.driver.cookies.add({"_jc_save_toStation": self.ends}) self.driver.cookies.add({"_jc_save_fromDate": self.dtime}) self.driver.find_by_text(u"查询").click()
运行代码:
python tickets.py 上海 广州 2018-12-25
最后手动点一下的12306验证码,抢到票后确认支付就行啦。
二、抢红包
1、实现微信自动抢红包
微信自动抢红包的实现方法,主要实现以下几个功能:
- 自动拆开屏幕上出现的红包
- 处于桌面或聊天列表时接收到红包信息时自动进入聊天界面并拆红包
- 日志功能,记录抢红包的详细日志
实现原理:
- 利用AccessibilityService辅助服务,监测屏幕内容,实现自动拆红包的目的。
- 利用ActiveAndroid数据库简单记录红包日志
- 利用preference实现监控选项纪录
最终界面:
抢红包核心代码:
AccessibilityService配置
android:accessibilityEventTypes 设置触发监听回调的事件类型; android:packageNames 设置监听的应用,这里监听的是微信,因此填上微信的包名com.tencent.mm <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" android:description="@string/accessibility_description" android:notificationTimeout="100" android:packageNames="com.tencent.mm" android:settingsActivity="com.oden.annotations.app.activity.ManActivity" />
在AndroidManifest.xml中声明:
<service android:name=".app.service.HongbaoService_" android:enabled="true" android:exported="true" android:label="@string/app_name" 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_config" /> </service>
抢红包实现代码
接收系统发送来的AccessibilityEvent
private static final String GET_RED_PACKET = "领取红包"; private static final String CHECK_RED_PACKET = "查看红包"; private static final String RED_PACKET_PICKED = "手慢了,红包派完了"; private static final String RED_PACKET_PICKED2 = "手气"; private static final String RED_PACKET_PICKED_DETAIL = "红包详情"; private static final String RED_PACKET_SAVE = "已存入零钱"; private static final String RED_PACKET_NOTIFICATION = "[微信红包]"; @Override public void onAccessibilityEvent(AccessibilityEvent event) { L.d("RECEIVE EVENT!"); if (watchedFlags == null) return; /* 检测通知消息 */ if (!mMutex) { if (watchedFlags.get("pref_watch_notification") && watchNotifications(event)) return; if (watchedFlags.get("pref_watch_list") && watchList(event)) return; } if (!watchedFlags.get("pref_watch_chat")) return; this.rootNodeInfo = event.getSource(); if (rootNodeInfo == null) return; mReceiveNode = null; mUnpackNode = null; checkNodeInfo(); /* 如果已经接收到红包并且还没有戳开 */ if (mLuckyMoneyReceived && !mLuckyMoneyPicked && (mReceiveNode != null)) { mMutex = true; AccessibilityNodeInfo cellNode = mReceiveNode; cellNode.getParent().performAction(AccessibilityNodeInfo.ACTION_CLICK); mLuckyMoneyReceived = false; mLuckyMoneyPicked = true; L.d("正在打开!"); } /* 如果戳开但还未领取 */ if (mNeedUnpack && (mUnpackNode != null)) { AccessibilityNodeInfo cellNode = mUnpackNode; cellNode.performAction(AccessibilityNodeInfo.ACTION_CLICK); mNeedUnpack = false; L.d("正在领取!"); } if (mNeedBack) { performGlobalAction(GLOBAL_ACTION_BACK); mMutex = false; mNeedBack = false; L.d("正在返回!"); //总次数和金额统计 if (isGetMoney) { T.showShort(this, "抢到一个红包: " + gotMoney + "元!"); totalMoney = totalMoney + gotMoney; totalSuccessNum++; myPrefs.totalMoney().put(totalMoney); myPrefs.successNum().put(totalSuccessNum); L.d("totalMoney: " + totalMoney); L.d("totalSuccessNum: " + totalSuccessNum); saveToLog(hongbaoInfo); isGetMoney = false; } } }
检测监听事件的节点信息
private void checkNodeInfo() { L.d("checkNodeInfo!"); if (this.rootNodeInfo == null) return; /* 聊天会话窗口,遍历节点匹配“领取红包”和"查看红包" */ List<AccessibilityNodeInfo> nodes1 = this.findAccessibilityNodeInfosByTexts(this.rootNodeInfo, new String[]{ GET_RED_PACKET, CHECK_RED_PACKET}); if (!nodes1.isEmpty()) { L.d("!nodes1.isEmpty()"); AccessibilityNodeInfo targetNode = nodes1.get(nodes1.size() - 1); if ("android.widget.LinearLayout".equals(targetNode.getParent().getClassName()))//避免被文字干扰导致外挂失效 { if (this.signature.generateSignature(targetNode)) { mLuckyMoneyReceived = true; mReceiveNode = targetNode; L.d("signature:" + this.signature.toString()); } } else { L.d("this is text"); } return; } List<AccessibilityNodeInfo> nodes2 = this.findAccessibilityNodeInfosByTexts(this.rootNodeInfo, new String[]{ "拆红包"}); if (!nodes2.isEmpty()) { L.d("node2 != null"); for (AccessibilityNodeInfo nodeInfo : nodes2) { if (nodeInfo.getClassName().equals("android.widget.Button")) nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } else { /* 戳开红包,红包还没抢完,遍历节点匹配“拆红包” */ AccessibilityNodeInfo node2 = (this.rootNodeInfo.getChildCount() > 3) ? this.rootNodeInfo.getChild(3) : null; if (node2 != null && node2.getClassName().equals("android.widget.Button")) { mUnpackNode = node2; mNeedUnpack = true; isToGetMoney = true; L.d("find red packet!"); return; } } /* 戳开红包,红包已被抢完,遍历节点匹配“已存入零钱”和“手慢了” */ if (mLuckyMoneyPicked) { List<AccessibilityNodeInfo> nodes3 = this.findAccessibilityNodeInfosByTexts(this.rootNodeInfo, new String[]{ RED_PACKET_PICKED, RED_PACKET_SAVE, RED_PACKET_PICKED2, RED_PACKET_PICKED_DETAIL}); if (!nodes3.isEmpty()) { L.d("!nodes3.isEmpty()"); if (rootNodeInfo.getChildCount() > 1) { L.d("RED_PACKET_PICKED!"); } else { L.d("nodes3.get(0).toString(): " + nodes3.get(0).getText().toString()); if (!nodes3.get(0).getText().toString().equals(RED_PACKET_PICKED_DETAIL)) { AccessibilityNodeInfo targetNode = nodes3.get(nodes3.size() - 1); hongbaoInfo.getInfo(targetNode); if (isToGetMoney) { isGetMoney = true; isToGetMoney = false; gotMoney = hongbaoInfo.getMoney(); L.d("gotMoney: " + gotMoney); } L.d("RED_PACKET_SAVE!"); L.d("hongbaoInfo: " + hongbaoInfo.toString()); } else { L.d("this packet is myself!"); } } mNeedBack = true; mLuckyMoneyPicked = false; } } }
主要通过检测“领取红包”等关键文字信息来判断是否有新红包
检测收到红包时判断是否"android.widget.LinearLayout",屏蔽聊天信息中的文字干扰
拆红包时,由于微信版本可能不同,同时进行两种判断,以兼容部分版本
拆完红包需自动返回,有以下几种情况:抢到了,手慢了,以及该红包是自己发出的红包
下面是监听聊天列表的代码:
private boolean watchList(AccessibilityEvent event) { // Not a message if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED || event.getSource() == null) return false; List<AccessibilityNodeInfo> nodes = event.getSource().findAccessibilityNodeInfosByText(RED_PACKET_NOTIFICATION); if (!nodes.isEmpty()) { AccessibilityNodeInfo nodeToClick = nodes.get(0); CharSequence contentDescription = nodeToClick.getContentDescription(); if (contentDescription != null && !lastContentDescription.equals(contentDescription)) { nodeToClick.performAction(AccessibilityNodeInfo.ACTION_CLICK); lastContentDescription = contentDescription.toString(); return true; } } return false; }
下面是监听通知信息的代码:
private boolean watchNotifications(AccessibilityEvent event) { // Not a notification if (event.getEventType() != AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) return false; // Not a hongbao String tip = event.getText().toString(); if (!tip.contains(RED_PACKET_NOTIFICATION)) return true; Parcelable parcelable = event.getParcelableData(); if (parcelable instanceof Notification) { Notification notification = (Notification) parcelable; try { notification.contentIntent.send(); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } } return true; }
红包信息的获取,及日志的存储:
通过获取节点的子信息,分别获得红包发送者及抢到的金额、抢红包时间等信息,建立简单的表单分别记录该信息。
@Table(name = "HongbaoInfos") public class HongbaoInfo extends Model { private int month; private int day; private int hour; private int min; private int sec; @Column(name = "sender") public String sender; @Column(name = "money") public String money; @Column(name = "time") public String time; public void getInfo(AccessibilityNodeInfo node) { AccessibilityNodeInfo hongbaoNode = node.getParent(); sender = hongbaoNode.getChild(0).getText().toString(); money = hongbaoNode.getChild(2).getText().toString(); time = getStringTime(); } private String getStringTime() { Calendar c = Calendar.getInstance(); month = c.get(Calendar.MONTH) + 1; day = c.get(Calendar.DAY_OF_MONTH); hour = c.get(Calendar.HOUR_OF_DAY); min = c.get(Calendar.MINUTE); sec = c.get(Calendar.SECOND); return month+"月"+day+"日 "+hour+":"+min+":"+sec; } @Override public String toString() { return "HongbaoInfo [sender=" + sender + ", money=" + money + ", time=" + time + "]"; } public static List<HongbaoInfo> getAll() { return new Select() .from(HongbaoInfo.class) .orderBy("Id ASC") .execute(); } public static void deleteALL() { new Delete().from(HongbaoInfo.class).execute(); } public float getMoney() { return Float.parseFloat(money); } public String getSender() { return sender; } public String getTime() { return time; } }
存储操作:
private void saveToLog(HongbaoInfo hongbaoInfo) { if (watchedFlags.get("pref_etc_log")) { HongbaoInfo hongbaoInfo1 = new HongbaoInfo(); hongbaoInfo1 = hongbaoInfo; hongbaoInfo1.save(); } else { L.d("log closed!"); } }
以上是微信自动抢红包方法
2、实现QQ自动抢红包
(一)抢红包流程:
- 通知栏收到QQ的消息,发现是QQ红包,模拟点击消息进入聊天页面
- 检索页面上的所有元素,发现有包含“点击拆开”的字眼,就模拟点击打开红包窗口
- 一两秒后执行Back操作,关闭红包窗口。
- 继续等待消息来到。
(二)实现功能:
- 锁屏抢红包(不可以有密码或者图案之类的锁屏)
- 口令红包,自动输入口令并且发送
- 抢完红包后,自动回复感谢语,可在红包设置里自行设置内容
- 其他的功能就没继续往下做了,知道方法,其他都可能慢慢研究出来。
(三)利用抢红包辅助功能类完成QQ抢红包,类中有用到QQConstant类,代码如下:
/** * 描述:QQ抢红包服务 */ public class EnvelopeService extends BaseAccessibilityService { //锁屏、解锁相关 private KeyguardManager.KeyguardLock kl; //唤醒屏幕相关 private PowerManager.WakeLock wl = null; private long delayTime = 0;//延迟抢的时间 /** * 描述:所有事件响应的时候会回调 */ @Override public void onAccessibilityEvent(AccessibilityEvent event) { //验证抢红包的开关 if (!invalidEnable()) { return; } //事件类型 int eventType = event.getEventType(); //获取包名 CharSequence packageName = event.getPackageName(); if (TextUtils.isEmpty(packageName)) { return; } switch (eventType) { //状态栏变化 case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: if (QQConstant.QQ_PACKAGE_NAME.equals(packageName)) { //处理状态栏上QQ的消息,如果是红包就跳转过去 progressQQStatusBar(event); } break; //窗口切换的时候回调 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: if (QQConstant.QQ_PACKAGE_NAME.equals(packageName)) { //处理正在QQ聊天窗口页面,有其他群或者人有新的红包提醒,跳转过去。 progressNewMessage(event); //处理聊天页面的红包 progressQQChat(event); } break; } } /** * 描述:处理新消息 */ private void progressNewMessage(AccessibilityEvent event) { if (event == null) { return; } AccessibilityNodeInfo source = event.getSource(); if (source == null) { return; } //根据event的source里的text,来判断这个消息是否包含[QQ红包]的字眼,有的话就跳转过去 CharSequence text = source.getText(); if (!TextUtils.isEmpty(text) && text.toString().contains(QQConstant.QQ_ENVELOPE_KEYWORD)) { performViewClick(source); } } /** * 描述:验证抢红包是否开启 */ private boolean invalidEnable() { return SettingConfig.getInstance().getReEnable(); } /** * 描述:处理QQ状态栏 */ 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)) { //说明存在红包弹窗,马上进去 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 { //要跳转之前,先进行解锁屏幕,然后再跳转,有可能你现在屏幕是锁屏状态,先进行解锁,然后打开页面,有密码的可能就不行了 wakeUpAndUnlock(MyApp.context); //跳转 pendingIntent.send(); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } } } } } } /** * 描述:处理QQ聊天红包 */ public void progressQQChat(AccessibilityEvent event) { if (TextUtils.isEmpty(event.getClassName())) { return; //如果当前页面是聊天页面或者当前的描述信息是"返回消息界面",就肯定是对话页面 } //验证当前事件是否符合查询页面上的红包 if (!invalidEnvelopeUi(event)) { return; } //延迟点击红包,防止被检测到开了抢红包,不过感觉还是感觉会被检测到,应该有的效果吧... try { Thread.sleep(delayTime); } catch (InterruptedException e) { e.printStackTrace(); } //普通红包,检索点击拆开的字眼。 List<AccessibilityNodeInfo> envelope = findViewListByText(QQConstant.QQ_CLICK_TAKE_APART, false); //处理普通红包 progressNormal(envelope); //口令红包,检索口令红包的字眼。 List<AccessibilityNodeInfo> passwordList = findViewListByText(QQConstant.QQ_CLICK_PASSWORD_DIALOG, false); //处理口令红包 progressPassword(passwordList); } /** * 描述:验证是否现在是在聊天页面,可以进行抢红包处理 * @param event */ public boolean invalidEnvelopeUi(AccessibilityEvent event) { //判断类名是否是聊天页面 if (!QQConstant.QQ_IM_CHAT_ACTIVITY.equals(event.getClassName().toString())) { return true; } //判断页面中的元素是否有点击拆开的文本,有就返回可以进行查询了 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)) { //如果文本中有点击拆开的字眼,就返回可以进行查询了 return true; } } } return false; } /** * 回到系统桌面 */ 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); } /** * 描述:处理普通红包 */ 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())) { //点击拆开红包 performViewClick(accessibilityNodeInfo); //回复感谢信息,根据配置文件中配置的回复信息回复 String reReplyMessage = SettingConfig.getInstance().getReReplyMessage(); if (!TextUtils.isEmpty(reReplyMessage)) { replyMessage(reReplyMessage); } } } //最后延迟事件触发返回事件,关闭红包页面 performBackClick(1200); } } /** * 描述:处理口令红包 * @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())) { //如果口令红包存在,就在输入框中进行输入,然后发送 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. 填写口令到编辑框上然后进行发送 replyMessage(key); //返回,关闭红包页面 performBackClick(1200); } } } } } } /** * 唤醒屏幕并解锁权限 * <uses-permission android:name="android.permission.WAKE_LOCK" /> */ @SuppressLint("Wakelock") @SuppressWarnings("deprecation") public void wakeUpAndUnlock(Context context) { // 点亮屏幕 wl.acquire(); // 释放 wl.release(); // 解锁 kl.disableKeyguard(); } /** * 描述:回复消息,无延迟 */ public void replyMessage(String key) { replyMessage(key, 0); } /** * 描述:回复消息 */ 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聊天页面发送消息按钮 AccessibilityNodeInfo sendMessage = findViewByID(QQConstant.QQ_CHAT_MESSAGE_SEND); //然后就按下发送按钮 if (sendMessage != null && Button.class.getName().equals(sendMessage.getClassName())) { performViewClick(sendMessage); } } } @Override public void onInterrupt() { } @Override protected void onServiceConnected() { super.onServiceConnected(); // 获取电源管理器对象 PowerManager pm = (PowerManager) MyApp.context .getSystemService(Context.POWER_SERVICE); // 获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是调试用的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"); //初始化屏幕的监听 ScreenListener screenListener = new ScreenListener(MyApp.context); screenListener.begin(new ScreenListener.ScreenStateListener() { @Override public void onScreenOn() { Log.e("ScreenListener", "屏幕打开了"); } @Override public void onScreenOff() { //在屏幕关闭的时候,进行锁屏,不执行的话,锁屏就失效了,因为要实现锁屏状态下也可以进行抢红包。 Log.e("ScreenListener", "屏幕关闭了"); if (kl != null) { kl.disableKeyguard(); kl.reenableKeyguard(); } } @Override public void onUserPresent() { Log.e("ScreenListener", "解锁了"); } }); } @Override public void onDestroy() { super.onDestroy(); } }
(四)QQ辅助服务里有用到的常量
public class QQConstant { //QQ的应用包名 public static final String QQ_PACKAGE_NAME = "com.tencent.mobileqq"; //状态栏红包关键字 public static final String QQ_ENVELOPE_KEYWORD = "[QQ红包]"; //QQ聊天页面 public static final String QQ_IM_CHAT_ACTIVITY = "com.tencent.mobileqq.activity.SplashActivity"; //点击拆开 public static final String QQ_CLICK_TAKE_APART = "点击拆开"; //口令红包 public static final String QQ_CLICK_PASSWORD_DIALOG = "口令红包"; //聊天页面,输入框ID public static final String QQ_CHAT_MESSAGE_INPUT = "com.tencent.mobileqq:id/input"; //聊天页面,发送按钮 public static final String QQ_CHAT_MESSAGE_SEND = "com.tencent.mobileqq:id/fun_btn"; }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- CSS实用技巧
- CSS实用技巧干货
- Python实用技巧,你不知道的7个好玩的Python技巧
- Kubernetes 实用技巧: 使用 ksniff 抓包
- 你可能不知道的 npm 实用技巧
- 高性能网站实用技巧之消息队列篇
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Flask Web开发实战
李辉 / 机械工业出版社 / 2018-8-1 / 129
这是一本面向Python程序员的,全面介绍Python Web框架Flask的书。关于本书的详细介绍、相关资源等更多信息可以访问本书的官方主页http://helloflask.com/book了解。 • 国内首本Flask著作,在内容上涵盖完整的Flask Web开发学习路径,在实践上包含完整的Flask Web程序开发流程。同时兼容Python2 .7和Python3.6。 • 内......一起来看看 《Flask Web开发实战》 这本书的介绍吧!