抢红包插件实现原理浅析
抢红包,先看效果图~
实现自动抢红包,解决问题有两点:
一:如何实时监听发红包的事件
二:如何在红包到来的时候自动进入页面并自动点击红包
【zhangke3016 http://blog.csdn.net/zhangke3016】
一、如何获取红包到来的事件
为了获取红包到来状态栏的变化,我们要用到一个类:Accessibility
许多Android使用者因为各种情况导致他们要以不同的方式与手机交互。
这包括了有些用户由于视力上,身体上,年龄上的问题致使他们不能看完整的屏幕或者使用触屏,也包括了无法很好接收到语音信息和提示的听力能力比较弱的用户。
Android提供了Accessibility功能和服务帮助这些用户更加简单地操作设备,包括文字转语音(这个不支持中文),触觉反馈,手势操作,轨迹球和手柄操作。
OK,了解到这一点,那么接下来就顺利点了,首先来看看Accessibility以及AccessibilityService的使用
- 新建一个类继承AccessibilityService,并在AndroidManifest文件里注册它:
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
<application>
<service android:name="com.zkhb.weixinqinghongbao.service.QiangHongBaoService"
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/qianghongbao_service_config" /></service>
</application>
在子类QiangHongBaoService里实现几个重要的重载方法:
onServiceConnected() - 可选。系统会在成功连接上你的服务的时候调用这个方法,在这个方法里你可以做一下初始化工作,例如设备的声音震动管理,也可以调用setServiceInfo()进行配置工作。
onAccessibilityEvent() - 必须。通过这个函数可以接收系统发送来的AccessibilityEvent,接收来的AccessibilityEvent是经过过滤的,过滤是在配置工作时设置的。onInterrupt() - 必须。这个在系统想要中断AccessibilityService返给的响应时会调用。在整个生命周期里会被调用多次。
onUnbind() - 可选。在系统将要关闭这个AccessibilityService会被调用。在这个方法中进行一些释放资源的工作。
然后在/res/xml/qianghongbao_service_config.xml:
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged"android:accessibilityFeedbackType="feedbackGeneric"android:accessibilityFlags=""android:canRetrieveWindowContent="true"android:description="@string/accessibility_description"android:notificationTimeout="100"android:packageNames="com.tencent.mm" />
二、主要关注点以及如何在红包到来的时候自动进入页面并自动点击红包
在onAccessibilityEvent方法中监听状态栏的变化,主要有:AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED、AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED、AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
在响应窗体以及窗体内容变化时处理相关逻辑,获取带微信消息时以下代码打开消息:
//将微信的通知栏消息打开Notification notification = (Notification) event.getParcelableData();PendingIntent pendingIntent = notification.contentIntent;try {pendingIntent.send();} catch (PendingIntent.CanceledException e) {e.printStackTrace();}
具体代码网上有很多,一般都是通过:findAccessibilityNodeInfosByText、findAccessibilityNodeInfosByViewId查找文本或者资源节点进行点击操作,但新版微信开红包页面进行了处理,没有文本信息,而如果采用:
(上图截取是用的DDMS中的 UI Automator Viewer,如图:Eclipse中:
或者在sdk的tools目录下:
)
图中resouces-id这种形式就可能出现这种情况:
在了解整个核心后,获取事件不外乎就是通过文本与id判断,那么就可以将文本改为图标方式,将id改为动态id(每次显示都是随机生成),这样一来就可以提高外挂的门槛。
如何进行规避呢,目前我想的是既然开红包的页面文本和ID都有可能会变,那我们能不能找个不变的进行判断呢,考虑过后,我觉得最可能不变的地方就是开红包这个按钮的位置,也就是图中的bounds,于是在思考过后有了下面的处理:
for (int i = 0; i < nodeInfo.getChildCount(); i++) {//Log.e("TAG", "getViewIdResourceName :"+nodeInfo.getChild(i).getViewIdResourceName());Rect outBounds = new Rect();nodeInfo.getChild(i).getBoundsInScreen(outBounds);int left_dp = px2dip(this, 400);int top_dp = px2dip(this, 1035);int right_dp = px2dip(this, 682);int bottom_dp = px2dip(this, 1320);int left_px = dip2px(this, left_dp);int top_px = dip2px(this, top_dp);int right_px = dip2px(this, right_dp);int bottom_px = dip2px(this, bottom_dp);Rect mStandar = new Rect(left_px,top_px,right_px,bottom_px);if(mStandar.contains(outBounds)){Log.e("TAG", "outBounds.left :"+outBounds.left+";outBounds.top :"+outBounds.top+";outBounds.right :"+outBounds.right+";outBounds.bottom :"+outBounds.bottom);nodeInfo.getChild(i).performAction(AccessibilityNodeInfo.ACTION_CLICK);break;}}
这里取的矩形区域要比按钮区域稍大点,然后判断到开红包页面按钮是否在我们预先设置的区域内,如果在,我们直接进行点击开红包操作:AccessibilityNodeInfo.ACTION_CLICK。
其他比如如何防止重复抢等细节问题,也是要处理的问题。
好了,直接放下关键代码,仅供参考:
package com.zkhb.weixinqinghongbao.service;import java.util.Date;
import java.util.List;import android.accessibilityservice.AccessibilityService;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.KeyguardManager;
import android.app.KeyguardManager.KeyguardLock;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;import com.zkhb.weixinqinghongbao.MainActivity;
import com.zkhb.weixinqinghongbao.R;
import com.zkhb.weixinqinghongbao.entity.HongBaoInfo;
import com.zkhb.weixinqinghongbao.util.DateFormatUtils;
import com.zkhb.weixinqinghongbao.util.LogUtil;/**** 抢红包服务*/
@SuppressLint("NewApi")
public class QiangHongBaoService extends AccessibilityService {// static final String TAG = "QiangHongBao";/** 微信的包名*/static final String WECHAT_PACKAGENAME = "com.tencent.mm";/** 红包消息的关键字*/static final String HONGBAO_TEXT_KEY = "[微信红包]";/** 红包消息的关键字*/static final String HONGBAO_TEXT_KEY1 = "微信红包";private static final int ENVELOPE_RETURN = 0;private static final String LOCK_TAG = "屏幕";Handler handler = new Handler();/** 是否在抢红包界面里*/
// public boolean isInMM=false;/** 是否可以点击*/
// public boolean ISCLICKED=false;/** 是否进入过拆红包界面*/public static boolean ISCOMINQIANGCHB=false;//真正的public static boolean ISCOMINQIANGCHB2=false;//真正的判断public static boolean ISCOMINQIANGCHB3=false;/** 是否来自通知栏*/private static boolean ISCOMNOTIFY=false;private PowerManager pm;//点亮屏幕private WakeLock mWakeLock;//解锁锁定屏幕private KeyguardLock keyguardLock;/**判断之前用户是否锁屏 */private static boolean islock=false;/**通知服务 */private NotificationManager n_manager;public void unlock(){if(pm==null){pm = (PowerManager) getApplication().getSystemService(Context.POWER_SERVICE);}boolean isScreenOn = pm.isScreenOn();//如果为true,则表示屏幕“亮”了,否则屏幕“暗”了。if(!isScreenOn){islock=true;KeyguardManager keyguardManager = (KeyguardManager)getSystemService(KEYGUARD_SERVICE);keyguardLock = keyguardManager.newKeyguardLock(LOCK_TAG);keyguardLock.disableKeyguard();mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, LOCK_TAG); mWakeLock.acquire();}}public void lock(){if(islock){//释放屏幕常亮锁if(null != mWakeLock) {mWakeLock.release();}//屏幕锁定if(keyguardLock!=null){keyguardLock.reenableKeyguard();}}}@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) {final int eventType = event.getEventType();LogUtil.info("事件---->" + event);//通知栏事件if(eventType == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {unlock();List<CharSequence> texts = event.getText();if(!texts.isEmpty()) {for(CharSequence t : texts) {String text = String.valueOf(t);if(text.contains(HONGBAO_TEXT_KEY)) {ISCOMNOTIFY=true;ISCOMINQIANGCHB=false;openNotify(event);break;}}}} else if(eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {unlock();openHongBao(event);
// AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
// List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText = nodeInfo.findAccessibilityNodeInfosByText("领取红包");
// if(findAccessibilityNodeInfosByText.isEmpty()){// isInMM=false;
// }else{// isInMM=true;
// }
// List<CharSequence> text = event.getText();
// if(text.size()>=0){// CharSequence charSequence = text.get(0);
if(charSequence.equals("微信")){ isInMM=true;
}else{ isInMM=false;
}
// }}else if(eventType==AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && ISCOMNOTIFY){unlock();openHongBao(event);List<AccessibilityNodeInfo> InfoText = getRootInActiveWindow().findAccessibilityNodeInfosByText("领取红包");if(!InfoText.isEmpty()){checkKey2();ISCOMNOTIFY=false;}}}/*@Overrideprotected boolean onKeyEvent(KeyEvent event) {//return super.onKeyEvent(event);return true;}*/@Overridepublic boolean onUnbind(Intent intent) {Toast.makeText(this, "断开抢红包服务", Toast.LENGTH_SHORT).show();ISCOMINQIANGCHB=false;islock=false;ISCOMINQIANGCHB2=false;ISCOMINQIANGCHB3=false;ISCOMNOTIFY=false;setNotification("已关闭抢红包小助手服务~~",Notification.FLAG_AUTO_CANCEL,"已关闭抢红包小助手服务~~~");return super.onUnbind(intent);}@Overridepublic void onInterrupt() {Toast.makeText(this, "中断抢红包服务", Toast.LENGTH_SHORT).show();}@Overrideprotected void onServiceConnected() {super.onServiceConnected();ISCOMINQIANGCHB=false;ISCOMINQIANGCHB2=false;ISCOMINQIANGCHB3=false;islock=false;ISCOMNOTIFY=false;setNotification("已开启抢红包小助手服务~~",Notification.FLAG_NO_CLEAR,"已开启抢红包小助手服务~~~");Toast.makeText(this, "连接抢红包服务", Toast.LENGTH_SHORT).show();}private void setNotification(String content,int flags,String title) {if(n_manager==null){n_manager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);}n_manager.cancelAll();Notification notification=new Notification(R.drawable.ic_launcher, content, System.currentTimeMillis());
// notification.defaults |= Notification.DEFAULT_VIBRATE;
// long[] vibrate = {0,100,200,300}; //0毫秒后开始振动,振动100毫秒后停止,再过200毫秒后再次振动300毫秒
// notification.vibrate=vibrate;notification.flags |= flags; //表明在点击了通知栏中的"清除通知"后,此通知不清除,Intent notificationIntent = new Intent(this,MainActivity.class); //点击该通知后要跳转的ActivityPendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(),0,notificationIntent,0);notification.setLatestEventInfo(getApplicationContext(), title, "进入微信抢红包~~", contentIntent);n_manager.notify(0, notification);}private void sendNotifyEvent(){AccessibilityManager manager= (AccessibilityManager)getSystemService(ACCESSIBILITY_SERVICE);if (!manager.isEnabled()) {return;}AccessibilityEvent event=AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);event.setPackageName(WECHAT_PACKAGENAME);event.setClassName(Notification.class.getName());CharSequence tickerText = HONGBAO_TEXT_KEY;event.getText().add(tickerText);manager.sendAccessibilityEvent(event);}/** 打开通知栏消息*/@TargetApi(Build.VERSION_CODES.JELLY_BEAN)private void openNotify(AccessibilityEvent event) {if(event.getParcelableData() == null || !(event.getParcelableData() instanceof Notification)) {return;}//将微信的通知栏消息打开Notification notification = (Notification) event.getParcelableData();PendingIntent pendingIntent = notification.contentIntent;try {pendingIntent.send();} catch (PendingIntent.CanceledException e) {e.printStackTrace();}}@TargetApi(Build.VERSION_CODES.JELLY_BEAN)private void openHongBao(AccessibilityEvent event) {if("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI".equals(event.getClassName())) {//点中了红包,下一步就是去拆红包ISCOMINQIANGCHB=true;ISCOMINQIANGCHB2=true;checkKey1();} else if("com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI".equals(event.getClassName())) {//拆完红包后看详细的纪录界面LogUtil.info("事件---->com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI");//nonething
// if(ISCOMINQIANGCHB){// ISCOMINQIANGCHB=false;
// }if(ISCOMINQIANGCHB2){ISCOMINQIANGCHB3=true;}else{ISCOMINQIANGCHB3=false;}checkKey3();ISCOMINQIANGCHB=true;ISCOMINQIANGCHB2=false;performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);if(getSharedPreferences("config", Context.MODE_PRIVATE).getBoolean("auto", false)){performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME);}lock();} else if("com.tencent.mm.ui.LauncherUI".equals(event.getClassName())) {
// isInMM=true;//在聊天界面,去点中红包LogUtil.info("事件---->com.tencent.mm.ui.LauncherUI");checkKey2();}}@SuppressLint("NewApi") @TargetApi(Build.VERSION_CODES.JELLY_BEAN)private void checkKey3() {AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();if(nodeInfo == null) {LogUtil.info("rootWindow为空333");return;}//TODOList<AccessibilityNodeInfo> findAccessibilityNodeInfosByText = nodeInfo.findAccessibilityNodeInfosByText("元");if(findAccessibilityNodeInfosByText.size()>=0){AccessibilityNodeInfo accessibilityNodeInfo2 = findAccessibilityNodeInfosByText.get(0).getParent();CharSequence money = accessibilityNodeInfo2.getChild(2).getText();CharSequence name = accessibilityNodeInfo2.getChild(0).getText();if(ISCOMINQIANGCHB3){HongBaoInfo info=new HongBaoInfo();info.setStrDateTime(DateFormatUtils.format("yyyy-MM-dd HH:mm:ss", new Date()));info.setStrMoney(money+"");info.setStrName(name+"");info.save();}Toast.makeText(getApplicationContext(), money+":::"+name, 0).show();}
// List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/aw8");
// AccessibilityNodeInfo accessibilityNodeInfo = findAccessibilityNodeInfosByViewId.get(0);
// CharSequence text = accessibilityNodeInfo.getText(); }private void checkKey1() {AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();if(nodeInfo == null) {LogUtil.info("rootWindow为空11111");return;}for (int i = 0; i < nodeInfo.getChildCount(); i++) {Log.e("TAG", "getViewIdResourceName :"+nodeInfo.getChild(i).getViewIdResourceName());Rect outBounds = new Rect();nodeInfo.getChild(i).getBoundsInScreen(outBounds);int left_dp = px2dip(this, 400);int top_dp = px2dip(this, 1035);int right_dp = px2dip(this, 682);int bottom_dp = px2dip(this, 1320);int left_px = dip2px(this, left_dp);int top_px = dip2px(this, top_dp);int right_px = dip2px(this, right_dp);int bottom_px = dip2px(this, bottom_dp);Rect mStandar = new Rect(left_px,top_px,right_px,bottom_px);if(mStandar.contains(outBounds)){Log.e("TAG", "outBounds.left :"+outBounds.left+";outBounds.top :"+outBounds.top+";outBounds.right :"+outBounds.right+";outBounds.bottom :"+outBounds.bottom);nodeInfo.getChild(i).performAction(AccessibilityNodeInfo.ACTION_CLICK);break;}
// nodeInfo.performAction(action)//[405,1042][675,1312]}//List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("拆红包");// List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/b5d");
// for(AccessibilityNodeInfo n : list) {// n.performAction(AccessibilityNodeInfo.ACTION_CLICK);
// }}private void checkKey2() {AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();if(nodeInfo == null) {LogUtil.info("rootWindow为空222222");return;}List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("领取红包");if(list.isEmpty()) {list = nodeInfo.findAccessibilityNodeInfosByText(HONGBAO_TEXT_KEY);for(AccessibilityNodeInfo n : list) {LogUtil.info("-->微信红包:" + n);n.performAction(AccessibilityNodeInfo.ACTION_CLICK);break;}} else {//最新的红包领起AccessibilityNodeInfo parent = list.get(list.size() - 1).getParent();
// Log.w(TAG, "ISCLICKED::"+ISCLICKED)!ISCLICKED;if(parent != null && !ISCOMINQIANGCHB) {parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);}
// for(int i = list.size() - 1; i >= 0; i --) {// AccessibilityNodeInfo parent = list.get(i).getParent();
// Log.i(TAG, "-->领取红包:" + parent);
// if(parent != null && parent.isClickable()) {// parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
// break;
// }
// }
// performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);}}/*** @param info 当前节点* @param matchFlag 需要匹配的文字* @param type 操作的类型*/@SuppressLint("NewApi") public void recycle(AccessibilityNodeInfo info, String matchFlag, int type) {if (info != null) {if (info.getChildCount() == 0) {CharSequence desrc = info.getContentDescription();switch (type) {case ENVELOPE_RETURN://返回if (desrc != null && matchFlag.equals(info.getContentDescription().toString().trim())) {if (info.isCheckable()) {info.performAction(AccessibilityNodeInfo.ACTION_CLICK);} else {performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);}}break;}} else {int size = info.getChildCount();for (int i = 0; i < size; i++) {AccessibilityNodeInfo childInfo = info.getChild(i);if (childInfo != null) {LogUtil.info("index: " + i + " info" + childInfo.getClassName() + " : " + childInfo.getContentDescription()+" : "+info.getText());recycle(childInfo, matchFlag, type);}}}}}@Overridepublic void onDestroy() {super.onDestroy();lock();}/** * 根据手机的分辨率从 dip 的单位 转成为 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 根据手机的分辨率从 px(像素) 的单位 转成为 dp */ public static int px2dip(Context context, float pxValue) {
// final float scale = context.getResources().getDisplayMetrics().density; return (int) (pxValue / 3 + 0.5f); //3是本人手机的设备密度}
}
AccessibilityService还可以用在智能安装、虚拟按键上都有很多应用,这样的实践只是给我们一种解决问题另外的一种思路,问题嘛,总还是要解决的。
抢红包插件实现原理浅析相关推荐
- android黑科技系列——微信抢红包插件原理解析和开发实现
一.前言 自从几年前微信添加抢红包的功能,微信的电商之旅算是正式开始正式火爆起来.但是作为Android开发者来说,我们在抢红包的同时意识到了很多问题,就是手动去抢红包的速度慢了,当然这些有很多原因导 ...
- Android微信抢红包插件原理和实现 适配微信6.6.1版本
Android微信抢红包插件原理和实现 适配微信6.6.1版本 一.前言 年关将至,小伙伴们又聊起了春节长假的旅行安排和各自家乡的年味习俗,不一而足.其中在各个微信群聊中抢红包也是为大家所津津乐道的. ...
- Python标准库queue模块原理浅析
Python标准库queue模块原理浅析 本文环境python3.5.2 queue模块的实现思路 作为一个线程安全的队列模块,该模块提供了线程安全的一个队列,该队列底层的实现基于Python线程th ...
- Python标准库threading模块Condition原理浅析
Python标准库threading模块Condition原理浅析 本文环境python3.5.2 threading模块Condition的实现思路 在Python的多线程实现过程中,在Linux平 ...
- Android 插件化原理学习 —— Hook 机制之动态代理
前言 为了实现 App 的快速迭代更新,基于 H5 Hybrid 的解决方案有很多,由于 webview 本身的性能问题,也随之出现了很多基于 JS 引擎实现的原生渲染的方案,例如 React Nat ...
- 第一篇: 词向量之Word2vector原理浅析
第一篇: 词向量之Word2vector原理浅析 作者 Aroundtheworld 2016.11.05 18:50 字数 1353 阅读 5361评论 1喜欢 9 一.概述 本文主要是从deep ...
- 【Android 插件化】Hook 插件化框架 ( hook 插件化原理 | 插件包管理 )
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
- 【Android 插件化】插件化原理 ( 类加载器 )
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
- SPI及其工作原理浅析
说明.文章摘自:SPI协议及其工作原理浅析 http://bbs.chinaunix.net/thread-1916003-1-1.html 一.概述. SPI, Serial Perripheral ...
- Android 插件化原理解析——Activity生命周期管理
之前的 Android插件化原理解析 系列文章揭开了Hook机制的神秘面纱,现在我们手握倚天屠龙,那么如何通过这种技术完成插件化方案呢?具体来说,插件中的Activity,Service等组件如何在A ...
最新文章
- 如何在简历中添加自己的CSDN博客链接
- hdu2852(2009多校第四场) 树状数组求区间第k大的数 两种方法
- Android --- no module 问题
- greenPlum资源隔离
- Spring5参考指南:IOC容器
- 为了金秋那沉甸甸的麦穗,我绝不辜负春天
- sql删除语句_推荐强大开源的数据库SQL语句审核平台,再也不用担心删除跑路了!...
- vue-cli3 DllPlugin 提取公用库
- const 指针_C语言学习日记(11)——const与指针
- 固定顶部(广告栏效果)
- 腾讯“立知”被指抄袭“即刻” APP,目前已被下线
- android性能调优的工具,神兵利器-Android 性能调优工具 Hugo
- python入门24 json模块
- 蓝桥杯2015年第六届C/C++省赛B组第三题-三羊献瑞
- 【操作系统】代码实践:先来先服务调度算法(FCFS),短进程优先调度算法(SJF),高响应比优先调度算法(HRRN)
- Wincc声音报警简单方法
- 员工计算机耗材管理,八大秘籍教你精细化管理科室耗材!
- 【Apache运维基础(4)】Apache的Rewrite攻略(1)
- 火狐资产2.6浏览器 下载_通过浏览器体验资产商店!
- Error response from daemon: Container 2c6d35b44a9862c63a6caf11a5622a33fe27979e12e51f9bd96f8dad98521c