iPhone 不越狱可以显示来电显示归属地归属地吗

科摩多软件管家 – 监控安装,并完全卸载程序
(快来投票)
Loading...
在安装科摩多软件管家后,右键任何程序安装包,选择 CPM 监控并安装(Install and monitor setup using CPM),科摩多软件管家就开始工作了,他会扫描所有的系统文件变化以及注册表等改变并保存下来,以便卸载的时候使用。不常驻内存,不用开机启动。
期间右下角会弹窗告诉你已经监控程序安装了:
这时科摩多软件管家列表里的程序就有了完整卸载按钮,没有通过扫描的安装程序只有标准卸载,我们知道很多标准卸载只是做做样子…
另外一个很实用的功能是卸载备份,只需前往设置页面,选择卸载前备份(Backup before uninstall),这样只要通过扫描的程序使用科摩多软件管家卸载后,就可以在你后悔的时候恢复了,并且不需要安装程序就能恢复:
所以,你觉着哪种软件管家靠谱呢?帮你守护家门,还是在你家里搞推销的?
P.S. 假期快乐,祝堵在路上的同学早点到站…
在用毛豆的墙。。。这个还真没注意过。安装软件用一个软件管家,卸载用完美卸载,应该差不错了吧~~~
按分类查看文章:
大家都在讨论些什么
: Tampermonkey 是 JS,Stylish 是 CSS.: 可能说的是迅雷极速版,迅雷阳台右边分类目录里点迅雷极速版: 然而那个不带广告的急速版,打开就报错: 为什么磁力链不能下载?: 笔记不能批量导出,这是硬伤啊: 试用了一下,书的质量比较高,都是出版社出版的正规图书,比那些全是网络小说的平台好得多。而且每天一小时可以逼自己每天按时读书,很不错的创意!: 这软件有什么意义?可以监控注册表然后方便做成绿色软件么?如果不是,那么系统的卸载功能和这个一样啊。
最热门标签
传说中的小众软件 让你的手机应用与众不同。
商业网站或未授权媒体不得复制、转载、使用本站内容。CentOS安装卸载memcache及JAVA示例
时间: 18:49:03
&&&& 阅读:136
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&&
原文地址:/zhongshengzhen/
先安装libevent,memcached依赖libevent的lib
[_64_81_centos download]#& wget&
[_64_81_centos download]#& tar zxvf libevent-1.2.tar.gz
[_64_81_centos download]# cd libevent-1.2
设置安装目录
[_64_81_centos libevent-1.2]# ./configure --prefix=/usr/
[_64_81_centos libevent-1.2]# make && make install
&测试是否安装成功
[_64_81_centos memcached-1.2.0]#& ls -al /usr/lib | grep libevent&
lrwxrwxrwx&& 1 root root&&&& 21 Jan 14 17:47 libevent-1.2.so.1 -& libevent-1.2.so.1.0.3
-rwxr-xr-x&& 1 root root 264056 Jan 14 17:47 libevent-1.2.so.1.0.3
-rw-r--r--&& 1 root root 430396 Jan 14 17:47 libevent.a
-rwxr-xr-x&& 1 root root&&& 814 Jan 14 17:47 libevent.la
lrwxrwxrwx&& 1 root root&&&& 21 Jan 14 17:47 libevent.so -& libevent-1.2.so.1.0.3
安装memcache
Memcache是一个hash表形式的缓存服务。用户缓存数据达到提供响应效率和处理高并发的情况。
[_64_81_centos download]#&wget&
[_64_81_centos download]# tar zxvf&memcached-1.2.0.tar.gz
[_64_81_centos download]#cd&memcached-1.2.0
[_64_81_centos memcached-1.2.0]# ./configure -with-libevent=/usr
[_64_81_centos memcached-1.2.0]# make
[_64_81_centos memcached-1.2.0]# make install
测试是否安装成功
[_64_81_centos memcached-1.2.0]#& ls -al /usr/local/bin/mem*&
-rwxr-xr-x 1 root root 113188 Jan 14 17:51 /usr/local/bin/memcached
-rwxr-xr-x 1 root root 117535 Jan 14 17:51 /usr/local/bin/memcached-debug
启动memcached&
[ ~]#&/usr/local/bin/memcached -d -m 512 -u root -l 127.0.0.1 -p 11211 -c 256 -P /tmp/memcached.pid
root&用户名
512缓存大小512M
192.168.137.33 本机ip
11211分配的端口
256是连接数
卸载memcached
1.结束memcached进程
# killall memcached
2.删除memcached目录及文件
# rm -rf /usr/local/memcached
# rm -f /etc/rc.d/init.d/memcached
3.关闭memcached开机启动
# chkconfig memcached off
4.把memcached移出开机启动
# chkconfig --del memcached
错误说明:
1、[_64_81_centos memcached-1.2.0]# /usr/local/bin/memcached -d -m 512 -u root -l 127.0.0.1 -p 11211 -c 256 -P /tmp/memcached.pid
/usr/local/bin/memcached: error while loading shared libraries: libevent-1.2.so.1: cannot open shared object file: No such file or directory
原因是memcached在/usr/lib/找不到文件,因而设置一个软连接如下:
[_64_81_centos lib]# ln -s /usr/lib/libevent-1.2.so.1& /usr/lib64/
&spring+java测试Memcache
spring配置:
&bean id="testCached" class="com.danga.MemCached.MemCachedClient"&
&constructor-arg&&value&neeaMemcachedPoolUserLogin&/value&&/constructor-arg&
&bean id="memcachedPooluserLogin" class="com.danga.MemCached.SockIOPool" factory-method="getInstance"
init-method="initialize" destroy-method="shutDown"&
&constructor-arg&&value&neeaMemcachedPoolUserLogin&/value&&/constructor-arg&
&property name="servers"&
&value&127.0.0.1:11211&/value&
&/property&
&property name="initConn"&&value&20&/value&&/property&
&property name="minConn"&&value&10&/value&&/property&
&property name="maxConn"&&value&800&/value&&/property&
&property name="maintSleep"&&value&30&/value&&/property&
&property name="nagle"&&value&false&/value&&/property&
&property name="socketTO"&&value&3000&/value&&/property&
JAVA代码:
@Componentpublic class SysCacheHelper { @Autowired @Qualifier("testCached") private MemCachedC
public boolean setSysCache(int categoryId, TSysConfig sysConfig){
return cache.set(Constants.SYS_PREFIX + categoryId, sysConfig, LoginedCacheHelper.get3DayCalendarTime(Constants.SYS_CACHE_EXPIRED_DAY)); } public TSysConfig getSysCache(int categoryId){
return (TSysConfig)cache.get(Constants.SYS_PREFIX + categoryId); } public boolean removeSysCache(int categoryId){
return cache.delete(Constants.SYS_PREFIX + categoryId); }}
可以调用方法查看memcached中的内容。
示例代码只是摘录重要片段。
&标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&原文:/zhongshengzhen/p/memcached.html
教程昨日排行
&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!Android 静默方式实现批量安装卸载应用程序的深入分析
字体:[ ] 类型:转载 时间:
本篇文章是对Android 静默方式实现批量安装卸载应用程序进行了详细的分析介绍,需要的朋友参考下
前段时间做了一个批量安装卸载应用程序的小应用,由于安装卸载应用程序的部分API是隐藏的,所以必须在ubuntu下下载Android系统源码,并编译之后使用MM命令编译生成APK文件,其实也难。思路是这样的,在XX/packages/apps目录下有一个PackageInstaller的应用程序,Android机器中安装卸载都是由这个应用程序完成的。但是它没有批量安装和卸载的功能,如果要在自己的应用程序中添加批量安装和卸载的功能,其实很简单,只需要参考PakcageInstaller里面的安装卸载代码加个循环就可以了。但值得注意的是在编译的过程中必须复制PackageInstaller里面的Android.mk文件,修改文件为工程目录名。好了,废话不再多说,下面是关键代码1、 Android.mk文件 代码如下:LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := PackageInstaller LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) 代码如下:&&& LOCAL_PATH:= $(call my-dir)& &&& include $(CLEAR_VARS)& &&& LOCAL_MODULE_TAGS := optional& &&& LOCAL_SRC_FILES := $(call all-subdir-java-files)& &&& LOCAL_PACKAGE_NAME := PackageInstaller& &&& LOCAL_CERTIFICATE := platform& &&& include $(BUILD_PACKAGE)& 2、PakcageInstaller.java文件(关键代码) 代码如下:&&& package cn.ceadic. &&& import java.io.F &&& import java.io.FileNotFoundE &&& import java.io.FileOutputS &&& import java.io.IOE &&& import android.content.C &&& import android.content.I &&& import android.content.pm.PackageI &&& import android.content.pm.PackageM &&& import android.content.pm.PackageManager.NameNotFoundE &&& import android.net.U &&& import android.util.L &&& import android.content.pm.IPackageInstallO &&& import android.content.pm.IPackageDeleteO &&& import android.os.FileU &&&& &&& public class PackageInstaller { &&&&&&& private File mTmpF &&&&&&& private final String TMP_FILE_NAME = "tmpCopy.apk"; &&&&&&& private final static String TAG = "PackInstaller"; &&&&&&& private Context mC &&&&&&& public PackageInstaller(Context context) { &&&&&&&&&&& mContext = &&&&&&& } &&&&&&&& &&&&&&& public void install(String path,String packageName){ &&&&&&&&&&&& Intent intent = new Intent(Intent.ACTION_VIEW); &&&&&&&&&&&& intent.setDataAndType(Uri.fromFile(new File(path)), &&&&&&&&&&&& "application/vnd.android.package-archive"); &&&&&&&&&&&& mContext.startActivity(intent); &&&&&&& } &&&&&&& public void instatllBatch(String path, String packageName) { &&&&&&&&&&& Log.i(TAG, "path=" + path); &&&&&&&&&&& int installFlags = 0; &&&&&&&&&&& PackageManager pm = mContext.getPackageManager(); &&&&&&&&&&& try { &&&&&&&&&&&&&&& PackageInfo pi = pm.getPackageInfo(packageName, &&&&&&&&&&&&&&&&&&&&&&& PackageManager.GET_UNINSTALLED_PACKAGES); &&&&&&&&&&&&&&& if (pi != null) { &&&&&&&&&&&&&&&&&&& installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; &&&&&&&&&&&&&&& } &&&&&&&&&&& } catch (NameNotFoundException e) { &&&&&&&&&&& } &&&&&&&&&&& if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { &&&&&&&&&&&&&&& Log.w(TAG, "Replacing package:" + packageName); &&&&&&&&&&& } &&&&&&&&&&& // Create temp file before invoking install api &&&&&&&&&&& mTmpFile = createTempPackageFile(path); &&&&&&&&&&& if (mTmpFile == null) { &&&&&&&&&&&&&&& // Message msg = mHandler.obtainMessage(INSTALL_COMPLETE); &&&&&&&&&&&&&&& // msg.arg1 = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; &&&&&&&&&&&&&&& // mHandler.sendMessage(msg); &&&&&&&&&&&&&&& &&&&&&&&&&& } &&&&&&&&&&& Uri mPackageURI = Uri.parse("file://" + mTmpFile.getPath()); &&&&&&&&&&& String installerPackageName = mContext.getIntent().getStringExtra( &&&&&&&&&&&&&&&&&&& Intent.EXTRA_INSTALLER_PACKAGE_NAME); &&&&&&&&&&& PackageInstallObserver observer = new PackageInstallObserver(); &&&&&&&&&&& pm.installPackage(mPackageURI, observer, installFlags, &&&&&&&&&&&&&&&&&&& installerPackageName); &&&&&&& } &&&&&&& private File createTempPackageFile(String filePath) { &&&&&&&&&&& File tmpPackageFile = mContext.getFileStreamPath(TMP_FILE_NAME); &&&&&&&&&&& if (tmpPackageFile == null) { &&&&&&&&&&&&&&& Log.w(TAG, "Failed to create temp file"); &&&&&&&&&&&&&&& &&&&&&&&&&& } &&&&&&&&&&& if (tmpPackageFile.exists()) { &&&&&&&&&&&&&&& tmpPackageFile.delete(); &&&&&&&&&&& } &&&&&&&&&&& // Open file to make it world readable &&&&&&&&&&& FileOutputS &&&&&&&&&&& try { &&&&&&&&&&&&&&& fos = openFileOutput(TMP_FILE_NAME, MODE_WORLD_READABLE); &&&&&&&&&&& } catch (FileNotFoundException e1) { &&&&&&&&&&&&&&& Log.e(TAG, "Error opening file " + TMP_FILE_NAME); &&&&&&&&&&&&&&& &&&&&&&&&&& } &&&&&&&&&&& try { &&&&&&&&&&&&&&& fos.close(); &&&&&&&&&&& } catch (IOException e) { &&&&&&&&&&&&&&& Log.e(TAG, "Error opening file " + TMP_FILE_NAME); &&&&&&&&&&&&&&& &&&&&&&&&&& } &&&&&&&&&&& File srcPackageFile = new File(filePath); &&&&&&&&&&& if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) { &&&&&&&&&&&&&&& Log.w(TAG, "Failed to make copy of file: " + srcPackageFile); &&&&&&&&&&&&&&& &&&&&&&&&&& } &&&&&&&&&&& return tmpPackageF &&&&&&& } &&&&&&& private class PackageInstallObserver extends IPackageInstallObserver.Stub { &&&&&&&&&&& public void packageInstalled(String packageName, int returnCode) { &&&&&&&&&&&&&&& // Message msg = mHandler.obtainMessage(INSTALL_COMPLETE); &&&&&&&&&&&&&&& // msg.arg1 = returnC &&&&&&&&&&&&&&& // mHandler.sendMessage(msg); &&&&&&&&&&&&&&& Log.i(TAG, "====INSTALL_COMPLETE"); &&&&&&&&&&& } &&&&&&& } &&&&&&& private class PackageDeleteObserver extends IPackageDeleteObserver.Stub { &&&&&&&&&&& public void packageDeleted(boolean succeeded) { &&& //&&&&&&&&&&& Message msg = mHandler.obtainMessage(UNINSTALL_COMPLETE); &&& //&&&&&&&&&&& msg.arg1 = succeeded?SUCCEEDED:FAILED; &&& //&&&&&&&&&&& mHandler.sendMessage(msg); &&&&&&&&&&&&&&& Log.i(TAG, "====UNINSTALL_COMPLETE"); &&&&&&&&&&& } &&&&&&& } &&&&&&& public void uninstall(String packageName){ &&&&&&&&&&& Uri packageURI = Uri.parse("package:" + packageName); &&&&&&&&&&& Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, &&&&&&&&&&& packageURI); &&&&&&&&&&& mContext.startActivity(uninstallIntent); &&&&&&& } &&&&&&& public void uninstallBatch(String packageName) { &&&&&&&&&&& PackageDeleteObserver observer = new PackageDeleteObserver(); &&&&&&&&&&& mContext.getPackageManager().deletePackage(packageName, observer, 0); &&&&&&& } &&& }&
代码如下:&&& package cn.ceadic.& &&& import java.io.F& &&& import java.io.FileNotFoundE& &&& import java.io.FileOutputS& &&& import java.io.IOE& &&& import android.content.C& &&& import android.content.I& &&& import android.content.pm.PackageI& &&& import android.content.pm.PackageM& &&& import android.content.pm.PackageManager.NameNotFoundE& &&& import android.net.U& &&& import android.util.L& &&& import android.content.pm.IPackageInstallO& &&& import android.content.pm.IPackageDeleteO& &&& import android.os.FileU& &&&&& &&& public class PackageInstaller {& &&&&&&& private File mTmpF& &&&&&&& private final String TMP_FILE_NAME = "tmpCopy.apk";& &&&&&&& private final static String TAG = "PackInstaller";& &&&&&&& private Context mC& &&&&&&& public PackageInstaller(Context context) {& &&&&&&&&&&& mContext =& &&&&&&& }& &&&&&&&&& &&&&&&& public void install(String path,String packageName){& &&&&&&&&&&&& Intent intent = new Intent(Intent.ACTION_VIEW);& &&&&&&&&&&&& intent.setDataAndType(Uri.fromFile(new File(path)),& &&&&&&&&&&&& "application/vnd.android.package-archive");& &&&&&&&&&&&& mContext.startActivity(intent);& &&&&&&& }& &&&&&&& public void instatllBatch(String path, String packageName) {& &&&&&&&&&&& Log.i(TAG, "path=" + path);& &&&&&&&&&&& int installFlags = 0;& &&&&&&&&&&& PackageManager pm = mContext.getPackageManager();& &&&&&&&&&&& try {& &&&&&&&&&&&&&&& PackageInfo pi = pm.getPackageInfo(packageName,& &&&&&&&&&&&&&&&&&&&&&&& PackageManager.GET_UNINSTALLED_PACKAGES);& &&&&&&&&&&&&&&& if (pi != null) {& &&&&&&&&&&&&&&&&&&& installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;& &&&&&&&&&&&&&&& }& &&&&&&&&&&& } catch (NameNotFoundException e) {& &&&&&&&&&&& }& &&&&&&&&&&& if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {& &&&&&&&&&&&&&&& Log.w(TAG, "Replacing package:" + packageName);& &&&&&&&&&&& }& &&&&&&&&&&& // Create temp file before invoking install api& &&&&&&&&&&& mTmpFile = createTempPackageFile(path);& &&&&&&&&&&& if (mTmpFile == null) {& &&&&&&&&&&&&&&& // Message msg = mHandler.obtainMessage(INSTALL_COMPLETE);& &&&&&&&&&&&&&&& // msg.arg1 = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;& &&&&&&&&&&&&&&& // mHandler.sendMessage(msg);& &&&&&&&&&&&&&&&& &&&&&&&&&&& }& &&&&&&&&&&& Uri mPackageURI = Uri.parse("file://" + mTmpFile.getPath());& &&&&&&&&&&& String installerPackageName = mContext.getIntent().getStringExtra(& &&&&&&&&&&&&&&&&&&& Intent.EXTRA_INSTALLER_PACKAGE_NAME);& &&&&&&&&&&& PackageInstallObserver observer = new PackageInstallObserver();& &&&&&&&&&&& pm.installPackage(mPackageURI, observer, installFlags,& &&&&&&&&&&&&&&&&&&& installerPackageName);& &&&&&&& }& &&&&&&& private File createTempPackageFile(String filePath) {& &&&&&&&&&&& File tmpPackageFile = mContext.getFileStreamPath(TMP_FILE_NAME);& &&&&&&&&&&& if (tmpPackageFile == null) {& &&&&&&&&&&&&&&& Log.w(TAG, "Failed to create temp file");& &&&&&&&&&&&&&&&& &&&&&&&&&&& }& &&&&&&&&&&& if (tmpPackageFile.exists()) {& &&&&&&&&&&&&&&& tmpPackageFile.delete();& &&&&&&&&&&& }& &&&&&&&&&&& // Open file to make it world readable& &&&&&&&&&&& FileOutputS& &&&&&&&&&&& try {& &&&&&&&&&&&&&&& fos = openFileOutput(TMP_FILE_NAME, MODE_WORLD_READABLE);& &&&&&&&&&&& } catch (FileNotFoundException e1) {& &&&&&&&&&&&&&&& Log.e(TAG, "Error opening file " + TMP_FILE_NAME);& &&&&&&&&&&&&&&&& &&&&&&&&&&& }& &&&&&&&&&&& try {& &&&&&&&&&&&&&&& fos.close();& &&&&&&&&&&& } catch (IOException e) {& &&&&&&&&&&&&&&& Log.e(TAG, "Error opening file " + TMP_FILE_NAME);& &&&&&&&&&&&&&&&& &&&&&&&&&&& }& &&&&&&&&&&& File srcPackageFile = new File(filePath);& &&&&&&&&&&& if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) {& &&&&&&&&&&&&&&& Log.w(TAG, "Failed to make copy of file: " + srcPackageFile);& &&&&&&&&&&&&&&&& &&&&&&&&&&& }& &&&&&&&&&&& return tmpPackageF& &&&&&&& }& &&&&&&& private class PackageInstallObserver extends IPackageInstallObserver.Stub {& &&&&&&&&&&& public void packageInstalled(String packageName, int returnCode) {& &&&&&&&&&&&&&&& // Message msg = mHandler.obtainMessage(INSTALL_COMPLETE);& &&&&&&&&&&&&&&& // msg.arg1 = returnC& &&&&&&&&&&&&&&& // mHandler.sendMessage(msg);& &&&&&&&&&&&&&&& Log.i(TAG, "====INSTALL_COMPLETE");& &&&&&&&&&&& }& &&&&&&& }& &&&&&&& private class PackageDeleteObserver extends IPackageDeleteObserver.Stub {& &&&&&&&&&&& public void packageDeleted(boolean succeeded) {& &&& //&&&&&&&&&&& Message msg = mHandler.obtainMessage(UNINSTALL_COMPLETE);& &&& //&&&&&&&&&&& msg.arg1 = succeeded?SUCCEEDED:FAILED;& &&& //&&&&&&&&&&& mHandler.sendMessage(msg);& &&&&&&&&&&&&&&& Log.i(TAG, "====UNINSTALL_COMPLETE");& &&&&&&&&&&& }& &&&&&&& }& &&&&&&& public void uninstall(String packageName){& &&&&&&&&&&& Uri packageURI = Uri.parse("package:" + packageName);& &&&&&&&&&&& Intent uninstallIntent = new Intent(Intent.ACTION_DELETE,& &&&&&&&&&&& packageURI);& &&&&&&&&&&& mContext.startActivity(uninstallIntent);& &&&&&&& }& &&&&&&& public void uninstallBatch(String packageName) {& &&&&&&&&&&& PackageDeleteObserver observer = new PackageDeleteObserver();& &&&&&&&&&&& mContext.getPackageManager().deletePackage(packageName, observer, 0);& &&&&&&& }& &&& }& 3、别忘记添加权限 代码如下:&&& &uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/& &&&&&&& &uses-permission android:name="android.permission.INSTALL_PACKAGES" /& &&&&&&& &uses-permission android:name="android.permission.DELETE_PACKAGES" /& &&&&&&& &uses-permission android:name="android.permission.CLEAR_APP_CACHE" /& &&&&&&& &uses-permission android:name="android.permission.READ_PHONE_STATE" /& &&&&&&& &uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" /&&
代码如下:&&& &uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/&& &&&&&&& &uses-permission android:name="android.permission.INSTALL_PACKAGES" /&& &&&&&&& &uses-permission android:name="android.permission.DELETE_PACKAGES" /&& &&&&&&& &uses-permission android:name="android.permission.CLEAR_APP_CACHE" /&& &&&&&&& &uses-permission android:name="android.permission.READ_PHONE_STATE" /&& &&&&&&& &uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" /&& 以上代码在Android2.1的SDK中编译通过,并正确批量安装卸载应用程序
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具[Android 测试] 性能回归测试之 MonkeyRunner使用、插件扩展、结合批处理
一、 MonkeyRunner简介
monkeyrunner也是一款安卓sdk自有的测试工具,开源,位于\sdk\tools下面,它主要做性能测试,回归测试,并且可以自定义测试扩展,和monkey是完全不同的。
monkeyrunner 工具提供了一组API ,通过这些 API 函数可以在代码之外(当然也可以直接在源代码直接使用)控制 Android设备和模拟器,通过 monkeyrunner,也可以写出一个脚本来安装、运行、测试、发送模拟操作流结果截图对比等等。
Android Studio monkeyrunner使用:
二、 MonkeyRunner安装
JDK Python编译器
配置环境变量
把Monkeyrunner的Tool配置到path
三、 录制、回放功能
monkeyrunner运行在PC上,逐行的去解释Python脚本代码,将命令发送到Android设备上戒者模拟器上执行,monkeyrunner除了支持Python脚本来执行测试,还可以通过录制回放的方式来执行测试。
通过monkeyrunner 脚本录制功能可以实现,录制和回放功能,但该功能目前提供操作徆简单只能运行比较简单的操作,而且要考虑不同机器的执行效率以及操作间的时间间隔
1.打开录制工具
在cmd命令行运行命令:
monkeyrunner recorder.py
即可运行recorder.py 脚本,用来启动录制工具,放置到sdk\tool的文件夹下,recorder.py源码如下
from com.android.monkeyrunner import MonkeyRunner as mr
from com.android.monkeyrunner.recorder import MonkeyRecorder as recorder
device = mr.waitForConnection()
recorder.start(device)
运行后将会看到出现这样的界面:
2. 录制工具简介
会看到标题栏、手机界面、右边事件列表
设置下一条命令的等待时间
Press a Button
发送MENU HOME SEARCH按钮的Press Down Up事件
Type Something
发送一些字符串
Export Action
将我们的脚本导出来
Refresh Display
刷新当前界面
3. 开始录制
打开了monkeyrunner recorder之后,在左边的手机界面即可操作手机,每一步操作都会在右边的列表生成事件
4. 录制处理
要注意的一点是,录制过程中monkeyrunner不会帮你设置等待时间,所以需要等待的界面,要点击标题栏的wait自己添加时间等待。
WAIT|{'seconds':2.0,}
操作完成之后,点击Export Action,把录制脚本保存为mr文件,放到sdk\tool下
在运行回放脚本playback.py+录制文件,即可在手机上执行录制的操作,
(ps: 这太鸡肋了)
(ps2: 需要先链接好手机,录制关掉)
monkeyrunner playback.py open.mr
playback.py源码,也是放到sdk\tools目录下:
import sys
from com.android.monkeyrunner import MonkeyRunner
CMD_MAP = {
'TOUCH': lambda dev, arg: dev.touch(**arg),
'DRAG': lambda dev, arg: dev.drag(**arg),
'PRESS': lambda dev, arg: dev.press(**arg),
'TYPE': lambda dev, arg: dev.type(**arg),
'WAIT': lambda dev, arg: MonkeyRunner.sleep(**arg)
def process_file(fp, device):
for line in fp:
(cmd, rest) = line.split('|')
# Parse the pydict
rest = eval(rest)
print 'unable to parse options'
if cmd not in CMD_MAP:
print 'unknown command: ' + cmd
CMD_MAP[cmd](device, rest)
def main():
file = sys.argv[1]
fp = open(file, 'r')
device = MonkeyRunner.waitForConnection()
process_file(fp, device)
fp.close();
if __name__ == '__main__':
四、 API和命令
- MonkeyRunner :此类提供了将monkeyrunner连接到设备或模拟器的方法。它还提供了为monkeyrunner程序创建UI和显示内置帮助的方法。
- MonkeyDevice :表示一个设备或模拟器。此类提供了用于安装和卸载包,启动Activity以及向应用程序发送键盘、触摸事件、运行测试包等方法。
- MonkeyImage :这个类提供了捕获屏幕方法,将位图转换为各种格式,比较两个MonkeyImage对象和保存图像等方法。
monkeyrunner -plugin
-plugin plugin_jar
(可选)指定一个内含monkeyrunner的jar文件,如要指定超过一个文件,可以多次使用此参数。
program_filename
如果提供此参数, monkeyrunner作为Python程序来运行。 如果未提供参数,则命令将启动交互式会话。
program_options
(可选)所指定程序的所需的参数。
具体的看上面的api网址。
五、 手工编写脚本
虽然 monkeyrunner 脚本使用 Python 语法编写,但它实际上是通过 Jython 来解释执行。 Jython 是 Python 的
实现,它将 Python 代码解释成 Java 上的字节码并执行,这种做法允许在 Python 中继承一个 Java 类型,可以调用任意的 Java API 。
测试脚本的一般格式:
# 在程序中引入 monkeyrunner 模块
from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice
# 连接到正在运行的设备戒模拟器上,返回一个 MonkeyDevice 对象
device = MonkeyRunner.waitForConnection()
# 安装待测应用, installPackage 会返回一个布尔值,来说明安装的结果
# device.installPackage ( &./CalcTest.apk&)
# 设置要启动的活动类名,有包名和活动类型组成
runComponent = &com.minstone.mdoctor/.activity.login.WelcomeActivity&
# 启动活动
device.startActivity(component = runComponent)
2. UI元素访问
通过坐标是比较快的,通过id定位比较慢。 坐标定位 手机不一样坐标也就不一样,id定位是每个手机都一样。
MR recorder 坐标获取、 其他工具获取
脚本中需要对不同同分辨率兼容
HierarchyViewer来解析控件ID,查看ID方式为:hierarchyviewer.bat工具
垃圾,好多手机用不了,现在都用UIAutomatorViewer, 速度慢
MonkeyDevice
只能进行简单的常用动作
这里我在网上找了一个例子,可以看看源码学习一下
#导入我们需要用到的包和类并且起别名
import sys
from com.android.monkeyrunner import MonkeyRunner as mr
from com.android.monkeyrunner import MonkeyDevice as md
from com.android.monkeyrunner import MonkeyImage as mi
from com.android.chimpchat.hierarchyviewer import HierarchyViewer #根据ID找到ViewNode,对viewnode的一些操作等
from com.android.monkeyrunner.easy import EasyMonkeyDevice
#提供了根据ID进行访问方法touch、drag等
from com.android.monkeyrunner.easy import By
#根据ID返回PyObject的方法
from com.android.hierarchyviewerlib.models import ViewNode as vn #代表一个控件,可获取控件属性
#connect device 连接设备
#第一个参数为等待连接设备时间
#第二个参数为具体连接的设备
device = mr.waitForConnection()
if not device:
print && sys.stderr,&fail&
sys.exit(1)
#定义要启动的Activity
componentName=&com.sky.jisuanji/.JisuanjizixieActivity&
#启动特定的Activity
device.startActivity(component=componentName)
mr.sleep(5.0)#延时时间结合自身机器环境需要调整
easy_device = EasyMonkeyDevice(device)#初始化EasyMonkeyDevice模块,必须放在startActivity之后,用来通过ID访问控件
hViewer = device.getHierarchyViewer() # 对当前UI视图进行解析
#执行1到9的累加操作
#1、通过坐标方式来获取
device.touch(93,241,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(238,490,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(249,235,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(238,490,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(370,231,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(238,490,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(106,315,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(238,490,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(253,323,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(238,490,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(397,328,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(238,490,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(96,411,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(238,490,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(270,406,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(238,490,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(402,423,device.DOWN_AND_UP)
mr.sleep(2.0)
device.touch(387,670,device.DOWN_AND_UP)
mr.sleep(2.0)
#takeSnapshot截图,获取程序运行界面截图
result0 = device.takeSnapshot()
#save to file 保存到文件
result0.writeToFile('./shot1.png','png');
#2、通过控件ID来获取
easy_device.touch(By.id('id/qingchu'),device.DOWN_AND_UP)
easy_device.touch(By.id('id/btn1'),device.DOWN_AND_UP)
easy_device.touch(By.id('id/jia'),device.DOWN_AND_UP)
easy_device.touch(By.id('id/btn2'),device.DOWN_AND_UP)
easy_device.touch(By.id('id/jia'),device.DOWN_AND_UP)
easy_device.touch(By.id('id/btn3'),device.DOWN_AND_UP)
easy_device.touch(By.id('id/jia'),device.DOWN_AND_UP)
easy_device.touch(By.id('id/btn4'),device.DOWN_AND_UP)
mr.sleep(3.0)
#takeSnapshot截图,获取程序运行界面截图
result1 = device.takeSnapshot()
#save to file 保存到文件
result1.writeToFile('./shot2.png','png');
if(result1.sameAs(result0,1.0)):#截图对比
print(&pic true&)
print(&pic false&) #全图100%对比 因为时间不同会输出false
#对比局部图片(去掉状态栏,因为状态栏时间会改变)
pic0= result0.getSubImage((4,41,400,700)) #局部结果图形对比
pic1= result1.getSubImage((4,41,400,700))
print (pic1.sameAs(pic0,1.0)) #输出true
#通过HierarchyViewer
content = hViewer.findViewById('id/text')
# 通过id查找对应元素返回viewnode对象来访问属性
text0 = hViewer.getText(content)
print text0.encode('utf-8')#打印结果
#通过By来获取
text1=easy_device.getText(By.id('id/text'))
print text1.encode('utf-8')#打印结果
device.press('KEYCODE_BACK', device.DOWN_AND_UP)
五、 插件扩展
jPython的jar下载:
MonkeyRunner.jar: 在sdk\tools 目录下
chimpchat.jar: 在sdk\tools 目录下
输入:编写一个 插件启动类,需实现mon.base.Predicate,该类在使用MonkeyRunner &plugin加载jar包时,首先启动,可以做一些初始化操作,一般可不实现任何内容。 编写插件所需实现的功能,可引入%android-sdk%\tools\lib下的monkeyrunner,jython ,guava等以及其他的jar包进行编写 将工程打包成.jar 文件,在 .jar文件的manifest中添加键MonkeyRunnerStartupRunner ,值为第一步的启动类,完成打包。
插件包不能使用android SDK中的jar包。 将生成的plugin.jar文件复制到%android-sdk%\tools\lib文件夹下或修改monkeyrunner.bat文件 ,&-Djava.ext.dirs=% frameworkdir%;% swt_path%;&这句中添加上plugin.jar文件所在文件夹路径。如果插件依赖其它jar包,需要跟插件包一起复制到上面的路径中。 否则可能会提在加载或使用插件是提示 ImportError : No module named XXX ,或初始化失败。
1. AS编写扩展插件
这里写一个案例:
工具: Android Studio2.2
1. 新建module
新建一个android library的module,名为testplugin。
2. 导入jar
导入三个jar,放到根目录的libs,右击add as library即可
jPython的jar下载:
MonkeyRunner.jar: 在sdk\tools 目录下
chimpchat.jar: 在sdk\tools 目录下
3. 编写Plugin
新建Pugin.java
package tpnet.
import com.android.internal.util.P
import org.python.util.PythonI
* Created by LITP on .
public class Plugin implements Predicate{
public boolean apply(PythonInterpreter pythonInterpreter) {
pythonInterpreter.set(&tpnet&,&Hello world&);
新建MyTestPlugin.java
package tpnet.
import com.android.chimpchat.core.TouchPressT
import com.android.monkeyrunner.MonkeyD
import com.android.monkeyrunner.doc.MonkeyRunnerE
import com.android.monkeyrunner.easy.By;
import com.android.monkeyrunner.easy.EasyMonkeyD
import org.python.core.PyO
* Created by LITP on .
public class MyTestPlugin {
private MonkeyDevice device =
private EasyMonkeyDevice easy_device =
@MonkeyRunnerExported(doc = &根据一个 MonkeyDevice实例创建Plugin.&, args = { &device& }, argDocs = { &要扩展的MonkeyDevice实例.& })
public MyTestPlugin(MonkeyDevice device) {
if(device != null)
this.device =
easy_device = new EasyMonkeyDevice(device);
@MonkeyRunnerExported(doc = &Hello Word Test.&, args = { && }, argDocs = { &print \&Hello World!\&.& })
public void test(PyObject[] args) {
System.out.println(&Hello World!&);
@MonkeyRunnerExported(doc = &Test Reboot Phone.&, args = { && }, argDocs = { &Reboot MobilPhone.& })
public void testReboot(PyObject[] args)
device.reboot(args, null);
//这个方法可以在脚本调用
@MonkeyRunnerExported(doc = &Plus 1-9.&, args = { && }, argDocs = { &Reboot MobilPhone.& })
public void plus() {
easy_device.touch(By.id(&id/qingchu&), TouchPressType.DOWN_AND_UP);
easy_device.touch(By.id(&id/btn1&),TouchPressType.DOWN_AND_UP);
easy_device.touch(By.id(&id/jia&),TouchPressType.DOWN_AND_UP);
easy_device.touch(By.id(&id/btn2&),TouchPressType.DOWN_AND_UP);
3. 修改gadle
修改gradle,添加task,下一步运行这个task,即可打包jar
apply plugin: 'com.android.library'
compileSdkVersion 24
buildToolsVersion &24.0.2&
defaultConfig {
minSdkVersion 15
targetSdkVersion 24
versionCode 1
versionName &1.0&
testInstrumentationRunner &android.support.test.runner.AndroidJUnitRunner&
buildTypes {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
lintOptions {
abortOnError false
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
compile 'com.android.support:appcompat-v7:24.2.1'
testCompile 'junit:junit:4.12'
compile files('libs/chimpchat.jar')
compile files('libs/jython-standalone-2.7.0.jar')
compile files('libs/monkeyrunner.jar')
task deleteOldJar(type: Delete) {
delete 'release/AndroidPlugin.jar'
//task to export contents as jar 将from(*)该目录下的文件复制到release/下 并更改名称为Bsdiff.jar
task exportJar(type: Copy) {
from('build/intermediates/bundles/release/')
into('release/')
include('classes.jar')
//Rename the jar
rename('classes.jar', 'AndroidPlugin.jar')
exportJar.dependsOn(deleteOldJar, build)
4. 打包jar
在右侧的gradle找到exportJar,双击运行,运行完毕即可在module根目录下的realease下看到AndroidPlugin.jar文件,
5. 在脚本中使用编写的插件
把生成的AndroidPlugin.jar文件拷贝到sdk\tools\lib目录下
编写脚本,导入自己的jar
# 导入自己的jar
from tpnet.testplugin import MyTestPlugin as tp
运行jar里面的方法
# 初始化自己的类
ttp=tp(device)
# 执行方法
ttq.plus()
六、结合批处理
集合自己编写的jar,利用一个批处理来运行MonkeyRunner,能自动获取当前连接的设备,获取apk安装包,不用修改源码。双击运行这个bat批处理即可
rem 获取当前运行设备
adb devices & devices.txt
rem 获取APK文件
dir apk /B & apk.txt
rem 运行monkeyrunner 脚本
monkeyrunner myScript.py -plugin lib/plugin.jar
myScript.py源码
from tpnet.testplugin import MyTestPlugin as tp
from com.android.monkeyrunner import MonkeyRunner as mr
# 定义列表
deviceslist = []
snapshot = []
templist = []
devices = []
# 打开文件
f = open(&devices.txt&)
# 循环读取文件添加到templist
while True:
line = f.readline()
templist.append(line.strip())
# 关闭文件流
templist.pop()
# 循环添加设备
for i in range(len(templist)):
deviceslist.append(templist[i].split('\t'))
# 读取启动activity
fc = open(&componentName.txt&)
complist = []
while True:
comp = fc.readline()
complist.append(comp.strip())
fc.close()
# 读取apk包
fp = open(&apk.txt&)
apklist = []
while True:
apk = fp.readline()
apklist.append(apk.strip())
print 'apk list :'
print apklist
print 'start componentName list :'
print complist
print 'devices list:'
print deviceslist
# 在手机上执行
for i in range(1,len(deviceslist)):
print 'current devices:'
print deviceslist[i]
devices.append(mr.waitForConnection(1.0,deviceslist[i][0]))
for j in range(len(apklist)):
devices[i-1].installPackage('apk/'+apklist[j])
for k in range(len(complist)):
print 'current start activity:'
print complist[k]
devices[i-1].startActivity(component=complist[k])
mr.sleep(5.0)
ttq=tp(devices[i-1])
ttq.plus()
七、 回归测试
回归测试是指修改了旧代码后,重新进行测试以确认修改没有引入新的错误或导致其他代码产生错误。
在MonkeyRunner里面主要是通过获取上次的截图和这次的截图进行对比判断
#从本地加载shot1-1.png上一次的截图进行结果对比
result0 = mr.loadImageFromFile('./shot1-1.png')
#对比局部图片
pic0= result0.getSubImage((4,41,400,700)) #局部结果图形对比
pic1= result1.getSubImage((4,41,400,700))
print (pic1.sameAs(pic0,1.0)) #输出true就是bug已经修改了,false不一样就是已经修好了
ok,谢谢观看

我要回帖

更多关于 越狱来电归属地插件 的文章

 

随机推荐