最近闲来无事写了一个 Robotium 的小工具,脑袋里 YY 着诸多功能的实现,没想到临门一脚把我搞吐血了,特来求一下实现思路,先阐述一下我目前实现的思路
一、项目背景:
一个 android 应用市场 APK
一个已经打包封装成 APK 的 robotium 脚本
二、各组件:
1.一个功能类似于 Monkey 的 robotium 脚本,动态获取当前设备屏幕宽,高,去掉信号栏高度,然后随机数生成一个坐标进行点击
2.由于有下载应用功能,下载应用后会自动弹出系统的应用安装界面,会导致脚本挂掉,所以添加了一个 Service,在程序启动时启动 Service 进行监听 Activity,判断当前 Activity 为系统安装界面或系统卸载界面,则唤醒被测程序 Activity
3.APK 首页是一个 ListView,想法是启动程序,首先展示当前手机上所有非系统的应用,然后点击某个被测程序条目,取得该条目对应应用的 mainActivity,传入到 robotium 脚本中,做到动态启动脚本(命令行启动)
三、目前遇到的问题:
以上各组件功能都已实现,唯独剩最后一步,将点击取到的对应 APK 条目的 mainActivity 字符串传给 Robotium Test 类出现问题,在脚本中打印 mainActivity 这个变量,脚本都会报空指针错误,好像 Robotium 启动后就把我这个变量销毁了一样,尝试过各种传值方法,以及使用 Service 进行传值,都没得到解决,特来求一解决思路
PS:已经解决了,证明 Robotium 封装成 APK,是和 APK 进程分进程的,尝试跨进程传值,使用 Handler 传值失败,最后用了最 SB 的方式,在 oncItemClick 的时候写 SD 卡文件,然后在 Robotium 脚本启动时读文件将 MainActivity 读出来
附代码(demo,未优化):
Robotium 脚本的:
package baih.Monkey;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Random;
import android.graphics.Rect;
import android.test.ActivityInstrumentationTestCase2;
import android.util.DisplayMetrics;
import android.util.Log;
import com.robotium.solo.Solo;
public class BaihMonkey extends ActivityInstrumentationTestCase2 {
public static String LAUNCHER_ACTIVITY_FULL_CLASSNAME ;
private static Class launcherActivityClass;
static{
File file=new File("/mnt/sdcard", "activityName.txt");
try {
BufferedReader fileReader = new BufferedReader (new FileReader(file));
String activityName = fileReader.readLine();
System.out.println(activityName);
LAUNCHER_ACTIVITY_FULL_CLASSNAME=activityName;
fileReader.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public BaihMonkey() throws ClassNotFoundException {
super(Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME));
}
private Solo solo;
String logtag="LikeMonkey_log";
@Override
protected void setUp() throws Exception {
solo = new Solo(getInstrumentation(), getActivity());
}
public void testMonkey() throws InterruptedException{
Thread.sleep(6000);
DisplayMetrics ty=new DisplayMetrics();
//getActivity().getWindowManager().getDefaultDisplay().getMetrics(ty);
Rect frame=new Rect();
solo.getCurrentActivity().getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight=frame.top;
solo.getCurrentActivity().getWindowManager().getDefaultDisplay().getMetrics(ty);
int x2=ty.widthPixels;
int y2=ty.heightPixels;
Log.e("baih", "x="+x2);
Log.e("baih", "y="+y2);
while(true)
{
Thread.sleep(2000);
Random setindex=new Random();
int setId=setindex.nextInt(20);
Log.e(logtag, "==="+setId);
switch (setId) {
case 2:
Log.e(logtag, "操作左滑动");
solo.scrollToSide(solo.LEFT, (float) 0.8); //左滑动
break;
case 5:
Log.e(logtag, "操作右滑动");
solo.scrollToSide(solo.RIGHT, (float) 0.8); //右滑动
break;
case 10:
Log.e(logtag, "操作返回");
solo.goBack(); //返回
break;
}
Random x=new Random();
int Rxindex=x.nextInt(x2);
int xIndex=Rxindex+10;
Random y=new Random();
int Ryindex=y.nextInt(y2);
int yIndex=Ryindex+statusBarHeight+5;
if(yIndex>=y2 || xIndex>=x2)
{
continue;
}
else
{
solo.clickOnScreen(xIndex, yIndex);
}
}
}
@Override
public void tearDown() throws Exception {
solo.finishOpenedActivities();
}
}
APK 首页,第三方应用列表的:
package baih.Monkey;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListAdapter;
import android.widget.ListView;
public class AppListActivity extends Activity {
/** Called when the activity is first created. */
ListView lv;
AppInfo adapter;
public static String LAUNCHER_ACTIVITY_FULL_CLASSNAME;
ArrayList<HashMap<String, Object>> items=new ArrayList<HashMap<String, Object>>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newfile);
Intent serviceIntent =new Intent(this,StartService.class);
startService(serviceIntent);
lv = (ListView) findViewById(R.id.lv);
final PackageManager pm= getPackageManager();
//得到PackageManager对象
final List<PackageInfo> packs = pm.getInstalledPackages(0);
//得到系统 安装的所有程序包的PackageInfo对象
Intent mainIntent =new Intent(Intent.ACTION_MAIN,null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> res=pm.queryIntentActivities(mainIntent, PackageManager.GET_ACTIVITIES);
for(ResolveInfo resolveInfo : res){
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("icon", resolveInfo.loadIcon(pm));
map.put("appName", resolveInfo.loadLabel(pm));
map.put("packageName", resolveInfo.activityInfo.packageName);
map.put("activityName", resolveInfo.activityInfo.name);
try {
ApplicationInfo itemApplicationInfo = pm.getApplicationInfo(resolveInfo.activityInfo.packageName, 0);
if((itemApplicationInfo.flags&ApplicationInfo.FLAG_SYSTEM)==0)
{
items.add(map);
}
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
adapter = new AppInfo(this, items, R.layout.applist_activity, new String[] {
"icon", "appName", "packageName" }, new int[] { R.id.icon,
R.id.appName, R.id.packageName });
//参数:Context,ArrayList(item的集合),item的layout,包含ArrayList中Hashmap的key的数组,key所对应的值相对应的控件id
lv.setAdapter(adapter);
lv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
//TARGET_PACKAGE_ID =(String) items.get(position).get("packageName");
LAUNCHER_ACTIVITY_FULL_CLASSNAME = (String) items.get(position).get("activityName");
File file=new File("/mnt/sdcard", "activityName.txt");
try {
if(!file.exists()){
boolean creatFile = file.createNewFile();
System.out.println("创建文件:" + creatFile);
}
BufferedWriter mWriter = new BufferedWriter(new FileWriter(file));
mWriter.write(LAUNCHER_ACTIVITY_FULL_CLASSNAME);
mWriter.flush();
mWriter.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Log.e("baih", "==activityName===="+LAUNCHER_ACTIVITY_FULL_CLASSNAME);
Runtime run=Runtime.getRuntime();
try {
Log.e("baih", "开始执行");
run.exec("am instrument -w baih.Monkey/android.test.InstrumentationTestRunner");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
Service 监听的:
package baih.Monkey;
import java.io.IOException;
import java.util.List;
import baih.Monkey.BaihMonkey;
import android.app.Activity;
import android.app.ActivityGroup;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.Instrumentation;
import android.app.KeyguardManager;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.os.Message;
import android.os.Process;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;
public class StartService extends Service {
public static String activityName;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
public void onCreate(){
IntentFilter intent =new IntentFilter("android.intent.action.VIEW");
//intent.addAction(Intent.ACTION_VIEW);
intent.setPriority(Integer.MAX_VALUE);
Toast.makeText(getApplicationContext(), "service已启动", 3000).show();
Log.e("baih", "===================service已启动");
final ActivityManager ActivityList=(ActivityManager)getApplicationContext().getSystemService(ACTIVITY_SERVICE);
new Thread(){
public void run(){
while(true)
{
List<RunningTaskInfo> acList=ActivityList.getRunningTasks(1);
RunningTaskInfo mTaskInfo;
mTaskInfo=acList.get(0);
String name=mTaskInfo.topActivity.getClassName();
// String setup="com.android.packageinstaller.PackageInstallerActivity";
String setup="com.android.packageinstaller.PackageInstallerActivity";
String uninstall="com.android.packageinstaller.UninstallerActivity";
Log.e("baih", name);
if(name.equals(setup) || name.equals(uninstall) )
{
List<RunningTaskInfo> ac1=ActivityList.getRunningTasks(2);
RunningTaskInfo ra1;
ra1=ac1.get(1);
String name1=ra1.topActivity.getClassName();
ComponentName componentName = ra1.topActivity;
Intent intent = new Intent();
//intent.setComponent(componentName);
intent.setClassName("com.stnts.suileyoo.gamecenter", "com.android.haoyouduo.StartupActivity");
intent.setAction(Intent.ACTION_MAIN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Log.e("baih", "===========操作返回");
Log.e("baih", "==========="+name1);
}
try {
Thread.sleep(4000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}.start();
}
public void onStart(){
final ActivityManager ma=(ActivityManager)getApplicationContext().getSystemService(ACTIVITY_SERVICE);
List<RunningTaskInfo> ac=ma.getRunningTasks(1);
RunningTaskInfo ra;
ra=ac.get(0);
String name=ra.topActivity.getClassName();
Log.e("baih", name);
if(name=="com.android.packageinstaller.PackageInstallerActivity")
{
Runtime run=Runtime.getRuntime();
try {
run.exec("input keyevent 4");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}