100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 【Android】使用deviceowner 配置手机设置 (Monkey自动化测试删去状态栏 设定输入

【Android】使用deviceowner 配置手机设置 (Monkey自动化测试删去状态栏 设定输入

时间:2019-10-14 03:05:59

相关推荐

【Android】使用deviceowner 配置手机设置 (Monkey自动化测试删去状态栏 设定输入

【Android】使用deviceowner 配置手机设置 (Monkey自动化测试删去状态栏、静音、设定输入法、APP自动权限授予、Kiosk模式打开)

背景:初步方法汇总1. 屏幕固定功能[ScreenPinning](/about/versions/android-5.0.html#ScreenPinning)2. 使用BroadcastReceiver打开和关闭WIFI3. 调用DeviceOwner中API,关闭状态栏。DeviceOwner设置和使用概念app结构代码分析1. 在res/xml目录下新建device_admin.xml文件;2. 注册一个广播继承DeviceAdminReceiver;3. 在清单文件里注册广播;4. 在其它类中激活设备管理器5. 设置device-admin权限6. 之后就是激活deviceOwner激活DeviceOwner时遇到的问题1. 最初我直接在PC命令行输入 adb dpm set-…… 这一大串命令的时候,报错 Error: Bad admin: ComponentInfo{com.example.deviceowner/com.example.deviceowner.MyDeviceAdminReceiver}2. 经典错误 java.lang.IllegalStateException: Not allowed to set the device owner because there are already some accounts on the deviceI. 删掉多的userInfoII. 删掉account7. 调用deviceOwner的API

背景:

需要使用Monkey进行自动化测试,但是测试时Monkey经常会下拉状态栏导致网络丢失等一系列问题,当前直接在百度上搜到的方法都是使用adb让屏幕全屏,但是我的测试机并不支持这个行为,所以需要找其它的方法。

初步方法汇总

在谷歌上搜索,找到了三种解决办法:

1. 屏幕固定功能ScreenPinning

这个功能可以在手机设置中开启,开启后可以固定手机只使用这个应用且屏蔽导航栏,开启需要使用虚拟按键。

所谓虚拟按键指的是屏幕下方出现返回、主页面、多任务 这些按钮,与之相对的是手势,也就是一般手机上推屏幕会出现多任务管理这个功能。

使用流程是:开启功能后,打开多任务管理,长按app,会出现锁定按钮,点击即可锁定。关闭是同时长按主页面和返回。

我的情况不太支持使用这个功能,首先我是对一些列app进行连续monkey测试,每次切换app锁定很困难,可能需要使用Appium之类的配合,其次,我需要app的截图,开启这个功能需要使用虚拟按键,app的截图会多出来虚拟按键的部分

2. 使用BroadcastReceiver打开和关闭WIFI

这个是我结合下面两个文章想到的

Android判断wifi状态 监听wifi连接

Android中使用BroadcastReceiver打开和关闭WIFI

完全可以试着写一个app监听wifi状态,在wifi关闭的时候自己设置打开wifi。

但是我没有实现这个想法。

3. 调用DeviceOwner中API,关闭状态栏。

最后一个方法就是使用DeviceOwner的API,

依旧是写个APP,调用Android中设备管理相关类的API

DevicePolicyManager下面的setStatusDisabled 函数

DeviceOwner设置和使用

概念

下面介绍几个概念:

device-owner:特殊的device-admin

设备管理者 device-admin

/guide/topics/admin/device-admin

app结构

常规的就是写一个最简单的app + 可以调用deviceOwner的一些设置

要完成调用deviceOwner首先,需要激活device-admin,此时可以使用一些deviceadmin相关的API设置,比如关闭相机等等,激活完device-admin再激活deviceOwner,之后就可以使用deviceOwner相关的API了

我自己这里是参照大佬的设计http://floatingmuseum.github.io//07/device-admin-practice

也写成了设置界面的样式

但是核心设置其实就几点:/XYScience/DeviceOwner

上面这个大佬的readme写的很清晰,我的app也基本参照两位大佬的代码

代码分析

下面对大佬的代码进行一下讲解

首先是device-admin编写:

1. 在res/xml目录下新建device_admin.xml文件;

<?xml version="1.0" encoding="utf-8"?><device-adminxmlns:android="/apk/res/android"><uses-policies></uses-policies></device-admin>

2. 注册一个广播继承DeviceAdminReceiver;

public class MyDeviceAdminReceiver extends DeviceAdminReceiver{@Overridepublic void onProfileProvisioningComplete(Context context, Intent intent) {super.onProfileProvisioningComplete(context, intent);}@Overridepublic void onEnabled(Context context, Intent intent) {super.onEnabled(context, intent);}@Overridepublic CharSequence onDisableRequested(Context context, Intent intent) {return super.onDisableRequested(context, intent);}@Overridepublic void onDisabled(Context context, Intent intent) {super.onDisabled(context, intent);}@Overridepublic void onPasswordChanged(Context context, Intent intent) {super.onPasswordChanged(context, intent);Logger.d("onPasswordChanged");}@Overridepublic void onPasswordFailed(Context context, Intent intent) {super.onPasswordFailed(context, intent);Logger.d("onPasswordFailed");}@Overridepublic void onPasswordSucceeded(Context context, Intent intent) {super.onPasswordSucceeded(context, intent);Logger.d("onPasswordSucceeded");}@Overridepublic void onPasswordExpiring(Context context, Intent intent) {super.onPasswordExpiring(context, intent);Logger.d("onPasswordExpiring");}/*** 获取ComponentName,DevicePolicyManager的大多数方法都会用到*/public static ComponentName getComponentName(Context context) {return new ComponentName(context.getApplicationContext(), MyDeviceAdminReceiver.class);}}

3. 在清单文件里注册广播;

<receiverandroid:name=".MyDeviceAdminReceiver"android:permission="android.permission.BIND_DEVICE_ADMIN"><meta-dataandroid:name="android.app.device_admin"android:resource="@xml/device_admin"/><intent-filter><action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/><action android:name="android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED"/><action android:name="android.app.action.DEVICE_ADMIN_DISABLED"/></intent-filter></receiver>

这样就完成了一个device-admin广播,之后就是激活和使用

4. 在其它类中激活设备管理器

激活的核心代码:

if (!devicePolicyManager.isAdminActive(comName)) {val intent = Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, comName)intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "激活此设备管理员后可免root停用应用")startActivityForResult(intent, 1)} else {Toast.makeText(this, "此App已激活设备管理器", Toast.LENGTH_SHORT).show()}

这段代码可以放在合适的地方使用,下面的代码,

dpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);

获取dpm在Fragment的onCreate中,

大佬app设置使用了PreferenceFragment(已过时,类似setting结构的fragment),点击对应preference后触发getAdmin()函数,激活deviceadmin,具体代码可以去看第一位大佬的github分析

@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);addPreferencesFromResource(R.xml.pref_deviceadmin);initListener();activity = DeviceAdminFragment.this.getActivity();if (dpm == null) {dpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);}if (pm == null) {pm = activity.getPackageManager();}mComponentName = MyDeviceAdminReceiver.getComponentName(activity);if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.LOLLIPOP){Logger.d("isProfileOwnerApp:"+dpm.isProfileOwnerApp(activity.getPackageName()));}}private boolean checkDeviceAdminEnabled() {return dpm.isAdminActive(mComponentName);}private void getDeviceAdmin() {if (checkDeviceAdminEnabled()) {ToastUtil.show("已激活");return;}Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,mComponentName);intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,getString(R.string.device_admin_description));startActivity(intent);}

5. 设置device-admin权限

在使用device-admin的API时,有些设置需要特殊的权限

权限常量

对应在xml中设置政策:

<device-admin xmlns:android="/apk/res/android" ><uses-policies><!-- 设置密码规则 --><limit-password /><!-- 监视屏幕解锁尝试次数 --><watch-login /><!-- 更改解锁密码 --><reset-password /><!-- 锁定屏幕 --><force-lock /><!-- 清除数据,恢复出厂模式,在不发出警告的情况下 --><wipe-data /><!-- 锁屏密码有效期 --><expire-password /><!-- 对存储的应用数据加密 --><encrypted-storage /><!-- 禁用锁屏信息 --><disable-keyguard-features/><!-- 禁用摄像头 --><disable-camera /></uses-policies></device-admin><!--和<application>同级 -->

6. 之后就是激活deviceOwner

现在一般有三种方式:我自己使用的是第二种adb的方式

利用ADB命令

$adb shell dpm set-device-owner com.example.deviceowner/.MyDeviceAdminReceiver

java.lang.IllegalStateException: Not allowed to set the device owner because there are already some accounts on the device

设置-账号中退出所有账户,然后重新尝试ADB设置

激活DeviceOwner时遇到的问题
1. 最初我直接在PC命令行输入 adb dpm set-…… 这一大串命令的时候,报错 Error: Bad admin: ComponentInfo{com.example.deviceowner/com.example.deviceowner.MyDeviceAdminReceiver}

如下图情况:会有一大堆使用说明最后有一点错误信息

D:\UIDump-master>adb shell dpm set-device-owner com.example.deviceowner/.MyDeviceAdminReceiver

usage: dpm [subcommand] [options]

usage: dpm set-active-admin [ --user <USER_ID> | current ]

usage: dpm set-device-owner [ --user <USER_ID> | currentEXPERIMENTAL] [ --name ]

usage: dpm set-profile-owner [ --user <USER_ID> | current ] [ --name ]

usage: dpm remove-active-admin [ --user <USER_ID> | current ] [ --name ]

dpm set-active-admin: Sets the given component as active admin for an existing user.

dpm set-device-owner: Sets the given component as active admin, and its package as device owner.

dpm set-profile-owner: Sets the given component as active admin and profile owner for an existing user.

dpm remove-active-admin: Disables an active admin, the admin must have declared android:testOnly in the application in its

manifest. This will also remove device and profile owners.

dpm clear-freeze-period-record: clears framework-maintained record of past freeze periods that the device went through. For use during feature development to prevent triggering restriction on setting freeze periods.

dpm force-network-logs: makes all network logs available to the DPC and triggers DeviceAdminReceiver.onNetworkLogsAvailable() if needed.

dpm force-security-logs: makes all security logs available to the DPC and triggers DeviceAdminReceiver.onSecurityLogsAvailable() if needed.

usage: dpm mark-profile-owner-on-organization-owned-device: [ --user <USER_ID> | current ]

Error: Bad admin: ComponentInfo{com.example.deviceowner/com.example.deviceowner.MyDeviceAdminReceiver}

当我先使用adb shell进入手机命令行,再使用dpm命令时就不会了

2. 经典错误 java.lang.IllegalStateException: Not allowed to set the device owner because there are already some accounts on the device

java.lang.IllegalStateException: Not allowed to set the device owner because there are already some accounts on the device

at android.os.Parcel.createExceptionOrNull(Parcel.java:2381)

at android.os.Parcel.createException(Parcel.java:2357)

at android.os.Parcel.readException(Parcel.java:2340)

at android.os.Parcel.readException(Parcel.java:2282)

at android.app.admin.IDevicePolicyManagerStubStubStubProxy.setDeviceOwner(IDevicePolicyManager.java:8665)

at mands.dpm.Dpm.runSetDeviceOwner(Dpm.java:203)

at mands.dpm.Dpm.onRun(Dpm.java:115)

at com.android.internal.os.BaseCommand.run(BaseCommand.java:60)

at mands.dpm.Dpm.main(Dpm.java:41)

at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)

at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:438)

这个错误很常见,简单说就是这个DeviceOwner本来就只是希望在新的测试设备上使用,所有不能有其他账户和他绑定。

具体解释可以看 Not allowed to set the device owner because there are already several users on the device

“设备所有者只能在未配置的设备上设置,除非它是由“adb”启动的,在这种情况下,如果没有与设备关联的帐户,我们会允许它”。因此,在使用 dpm 命令之前,请确保您没有与当前用户集关联的任何帐户(例如 Gmail) “

关于账号处理问题,我有看到别人比较详细的处理方法总结:

adb設置DeviceOwner發生問題

下面记录一下我自己采用的方法,就是简单直接全部删除了,本来我想备份一下来着,但是没成果。

I. 删掉多的userInfo

adb shell pm list users

Notallowedtosetthedevice owner because there are already some accounts on thedevice

删掉除了0以外的账户

adb shell pm remove-user 999

II. 删掉account

adb shell dunmpsys account

可以看到所有的账号

直接打开手机设置->里面有accounts,然后删掉就行,有些删除不了的账户可以直接卸载应用

最后再执行dpm就可以了

7. 调用deviceOwner的API

激活deviceOwner后即可调用需要的API,

我自己是使用了三种,状态栏不可用,静音、APP自动权限授予

具体有哪些函数可以去看安卓文档,功能还是很强大的

/reference/android/app/admin/DevicePolicyManager

这里给一个设置静音和状态栏不可用的样例,就是调用相应API

dpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);

dpm也是放在了onCreate中获取

private void setVolumeMuted() {boolean muted = SPUtil.getBoolean(activity, "muted", false);Logger.d("静音:" + muted);dpm.setMasterVolumeMuted(mComponentName, !muted);SPUtil.editBoolean(activity, "muted", !muted);}@TargetApi(Build.VERSION_CODES.M)private void disableStatusBar() {boolean result = dpm.setStatusBarDisabled(mComponentName,statusbar);statusbar = !statusbar;Logger.d("result:"+result+"...statusbar:"+statusbar);}

【Android】使用deviceowner 配置手机设置 (Monkey自动化测试删去状态栏 设定输入法 静音 APP自动权限授予 Kiosk模式打开)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。