背景,大概就是需要用手机给同一帐号转账几百笔,手动太麻烦,就写个自动化程序去完成。
关键技术是monkeyrunner,难点是手机验证码的自动化输入。
monkeyrunner是谷歌官方提供的,可以模拟手机点击的自动化测试工具,可以录制用户的点击坐标,具体可以参考:
http://blog.csdn.net/mad1989/article/details/38087737
同时monkeyrunner 需要用到python语言,python语言入门可以参考:
http://www.cnblogs.com/vamei/archive/2012/09/13/2682778.html
python官方的文档:
http://www.kuqin.com/abyteofpython_cn/index.html
初步感觉python的设计观点是力求让程序语言的代码简单,将更多的工作交给解释器来执行,变量不用声明以及指定类型,函数不用指定类型,变量都是对内存中的常量的引用。
回到正题,要实现这个功能需要三个部分。一、手机需要一个监听软件,将监听到的短信的验证信息读出,并放到一个电脑能访问的地方(sdcard)。二、执行python,python需要一个脚本文件用来控制输入。三、手机和电脑交互的桥梁管理软件,负责将手机上的验证码pull到电脑上面,并更新到脚本中去。
手机端需要监听短信
需要权限,包含读写sdcard文件:
<uses-permission android:name="android.permission.RECEIVE_SMS" >
</uses-permission>
<uses-permission android:name="android.permission.READ_SMS" >
</uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
设置监听:
public class SmsReceier extends BroadcastReceiver {
public static final String TAG = "ImiChatSMSReceiver";
public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(SMS_RECEIVED_ACTION)) {
SmsMessage[] messages = getMessagesFromIntent(intent);
for (SmsMessage message : messages) {
Log.v(TAG, message.getOriginatingAddress() + " : " +
message.getDisplayOriginatingAddress() + " : " +
message.getDisplayMessageBody() + " : " +
message.getTimestampMillis());
String mesBody = message.getDisplayMessageBody().substring(11,17); //这几位为短信验证码
File file = new File("/sdcard/number.txt");
try {
FileWriter fileWriter = new FileWriter(file);
fileWriter.write(mesBody);
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
电脑端的程序参照上面分享的monkeyrunner的教程。
最后管理软件,首先将sdcard包含的验证码的文件pull到电脑上面,因为服务器发给手机的短信的时间是不确定的,所以需要监测该文件是否是新短信的信息,验证码前后两天一般不同,利用这个可以验证是否是新的短信。最后两次模拟操作的时间间隔需要留够。
package com.czfree.SCRX;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import com.sun.jndi.url.iiopname.iiopnameURLContextFactory;
public class SCRX_Main {
public static int number_old = 0;
public static int number_new = 0;
public static String path = "C:\\czfree\\code\\Environ\\sdk\\tools";
public static String numberValue[]=new String[]{ //0到9数字的坐标
"TOUCH|{'x':624,'y':1828,'type':'downAndUp',}\n",
"TOUCH|{'x':303,'y':1328,'type':'downAndUp',}\n",
"TOUCH|{'x':546,'y':1288,'type':'downAndUp',}\n",
"TOUCH|{'x':816,'y':1300,'type':'downAndUp',}\n",
"TOUCH|{'x':300,'y':1528,'type':'downAndUp',}\n",
"TOUCH|{'x':580,'y':1504,'type':'downAndUp',}\n",
"TOUCH|{'x':820,'y':1512,'type':'downAndUp',}\n",
"TOUCH|{'x':307,'y':1632,'type':'downAndUp',}\n",
"TOUCH|{'x':526,'y':1640,'type':'downAndUp',}\n",
"TOUCH|{'x':806,'y':1684,'type':'downAndUp',}\n"
};
public static String OtherValue = "TOUCH|{'x':702,'y':720,'type':'downAndUp',}\n" + //输入验证码后面的步骤
"WAIT|{'seconds':1.0,}\n" +
"TOUCH|{'x':172,'y':1844,'type':'downAndUp',}\n"+
"WAIT|{'seconds':1.0,}\n"+
"TOUCH|{'x':590,'y':1380,'type':'downAndUp',}\n"+
"WAIT|{'seconds':1.0,}\n"+
"TOUCH|{'x':283,'y':1380,'type':'downAndUp',}\n"+
"WAIT|{'seconds':1.0,}\n"+
"TOUCH|{'x':1029,'y':1380,'type':'downAndUp',}\n"+
"WAIT|{'seconds':1.0,}\n"+
"TOUCH|{'x':492,'y':1372,'type':'downAndUp',}\n"+
"WAIT|{'seconds':1.0,}\n"+
"TOUCH|{'x':1026,'y':1376,'type':'downAndUp',}\n"+
"WAIT|{'seconds':1.0,}\n"+
"TOUCH|{'x':931,'y':1360,'type':'downAndUp',}\n"+
"WAIT|{'seconds':1.0,}\n"+
"TOUCH|{'x':749,'y':1140,'type':'downAndUp',}\n"+
"WAIT|{'seconds':2.0,}\n"+
"TOUCH|{'x':722,'y':1156,'type':'downAndUp',}\n"+
"WAIT|{'seconds':9.0,}\n"+
"TOUCH|{'x':344,'y':1092,'type':'downAndUp',}\n"+
"WAIT|{'seconds':3.0,}\n"+
"TOUCH|{'x':951,'y':388,'type':'downAndUp',}\n"+
"WAIT|{'seconds':4.0,}\n"+
"TOUCH|{'x':327,'y':1424,'type':'downAndUp',}\n"+
"WAIT|{'seconds':3.0,}\n"+
"TOUCH|{'x':472,'y':776,'type':'downAndUp',}\n"+
"WAIT|{'seconds':2.0,}\n"+
"TOUCH|{'x':239,'y':1376,'type':'downAndUp',}\n"+
"WAIT|{'seconds':2.0,}\n"+
"TOUCH|{'x':718,'y':812,'type':'downAndUp',}\n"+
"WAIT|{'seconds':2.0,}\n"+
"TOUCH|{'x':492,'y':1080,'type':'downAndUp',}\n"+
"WAIT|{'seconds':6.0,}\n"+
"TOUCH|{'x':634,'y':1392,'type':'downAndUp',}\n"+
"WAIT|{'seconds':6.0,}\n"+
"TOUCH|{'x':513,'y':880,'type':'downAndUp',}\n"+
"WAIT|{'seconds':2.0,}\n"+
"TOUCH|{'x':77,'y':1840,'type':'downAndUp',}\n"+
"WAIT|{'seconds':1.0,}";
public static boolean HasChange(){ //判断是否接到新的短信
try {
File file = new File(path + "\\number.txt");
BufferedReader br = new BufferedReader(new FileReader(file));
number_new = Integer.parseInt(br.readLine());
br.close();
if(number_new != number_old){
number_old = number_new;
// System.out.println(number_new+" "+ number_old);
return true;
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (NumberFormatException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
public static void ChangeAction() { //根据验证码更新脚本信息
try {
String wite = "WAIT|{'seconds':1.0,}\n";
int num = 100000;
int number_chu = number_new;
File file = new File(path + "\\action.mr");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
// String now = numberValue[0] + wite;
for( int i = 0; i < 6 ; i++){
bos.write("WAIT|{'seconds':0.5,}\n".getBytes());
bos.write("WAIT|{'seconds':0.5,}\n".getBytes());
int nownum = number_chu/num;
// now = now + numberValue[nownum] + wite;
bos.write(numberValue[nownum].getBytes());
System.out.println(nownum);
System.out.println(numberValue[nownum]);
bos.flush();
number_chu = number_chu%num;
num = num/10;
}
bos.write("WAIT|{'seconds':1.0,}\n".getBytes());
bos.write(OtherValue.getBytes());
bos.flush();
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new Thread(){
public void run() {
while(true){
Process process;
try {
process = Runtime.getRuntime().exec("adb pull /sdcard/number.txt " + path + "\\number.txt"); //pull手机中的验证码信息
process.waitFor();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//
if(!HasChange()){
System.out.println(number_new);
try {
sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else{
ChangeAction();
try {
//执行monkeyrunner操作
Process process1 = Runtime.getRuntime().exec(path + "\\monkeyrunner.bat "+ path + "\\monkey_playback.py " + path +"\\action.mr" );
process1.waitFor();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
}.start();
}
}