requestpermissions - request permission android studio
Cómo administrar los permisos de Runtime android malvavisco espresso (11)
Estoy usando espresso para las pruebas, pero a veces trato de obtener una imagen del almacenamiento externo y con Marshshallow necesito un permiso de Runtime, de lo contrario, se producirá un fallo de excepción y la prueba fallará.
androidTestCompile ''com.android.support.test:runner:0.4''
androidTestCompile ''com.android.support.test:rules:0.4''
androidTestCompile ''com.android.support.test.espresso:espresso-core:2.2.1''
androidTestCompile ''com.android.support.test.espresso:espresso-intents:2.2.1''
androidTestCompile(''com.android.support.test.espresso:espresso-contrib:2.2.1'') {
// this library uses the newest app compat v22 but the espresso contrib still v21.
// you have to specifically exclude the older versions of the contrib library or
// there will be some conflicts
exclude group: ''com.android.support'', module: ''appcompat''
exclude group: ''com.android.support'', module: ''support-v4''
exclude module: ''recyclerview-v7''
}
androidTestCompile ''junit:junit:4.12''
androidTestCompile ''com.squareup.retrofit:retrofit-mock:1.9.0''
androidTestCompile ''com.squareup.assertj:assertj-android:1.1.0''
androidTestCompile ''com.squareup.spoon:spoon-client:1.2.0''
¿Cómo puedo manejar ese derecho?
¿Debo escribir la prueba para los permisos de Runtime o hay una manera de deshabilitarla para la prueba?
¿Debo dar permisos antes de que se ejecuten las pruebas como dice ella aquí? https://www.youtube.com/watch?list=PLWz5rJ2EKKc-lJo_RGGXL2Psr8vVCTWjM&v=C8lUdPVSzDk
En la configuración de múltiples sabores, sea cual sea su tarea de instrumentación, digamos que connectedYourFlavorDebugAndroidTest
, puede especificar los permisos que desea otorgar antes de que se ejecuten las pruebas en todos los dispositivos conectados:
gradlew grantYourFlavorDebugPermissions -Ppermissions=android.permission.ACCESS_FINE_LOCATION,android.permission.ACCESS_COARSE_LOCATION
Vea el fragmento de código de sfjava a continuación para copiarlo en build.gradle
para generar la tarea grantYourFlavorDebugPermissions
Existe GrantPermissionRule en la biblioteca de compatibilidad de pruebas de Android , que puede utilizar en sus pruebas para otorgar un permiso antes de iniciar cualquier prueba.
@Rule public GrantPermissionRule permissionRule = GrantPermissionRule.grant(android.Manifest.permission.CAMERA);
He implementado una solución que aprovecha las clases de envoltura, anulando y construyendo la configuración de variantes. La solución es bastante larga de explicar y se encuentra aquí: https://github.com/ahasbini/AndroidTestMockPermissionUtils . No es necesario agregar ningún script en el sistema de compilación ni ejecutarse antes de ejecutar las pruebas.
Todavía no está empaquetado en un SDK, pero la idea principal es anular las funcionalidades de ContextWrapper.checkSelfPermission()
y ActivityCompat.requestPermissions()
para manipularlas y devolver los resultados ContextWrapper.checkSelfPermission()
la aplicación en los diferentes escenarios para probarlos como: el permiso fue denegado por lo tanto la aplicación lo solicitó y terminó con el permiso concedido. Este escenario ocurrirá incluso si la aplicación tenía el permiso todo el tiempo, pero la idea es que fue engañada por los resultados simulados de la implementación dominante.
Además, la implementación tiene una clase TestRule
llamada PermissionRule
que se puede usar en las clases de prueba para simular fácilmente todas las condiciones para probar los permisos sin problemas. También se pueden hacer afirmaciones como asegurarse de que la aplicación haya llamado requestPermissions()
por ejemplo.
Puede lograrlo fácilmente otorgando permiso antes de comenzar la prueba. Por ejemplo, si se supone que debe usar la cámara durante la prueba, puede otorgar el permiso de la siguiente manera
@Before
public void grantPhonePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getInstrumentation().getUiAutomation().executeShellCommand(
"pm grant " + getTargetContext().getPackageName()
+ " android.permission.CAMERA");
}
}
Puedes crear una tarea de Android para otorgar permiso:
android.applicationVariants.all { variant ->
def applicationId = variant.applicationId
def adb = android.getAdbExe().toString()
def variantName = variant.name.capitalize()
def grantPermissionTask = tasks.create("grant${variantName}Permissions") << {
"${adb} devices".execute().text.eachLine {
if (it.endsWith("device")){
def device = it.split()[0]
println "Granting permissions on devices ${device}"
"${adb} -s ${device} shell pm grant ${applicationId} android.permission.CAMERA".execute()
"${adb} -s ${device} shell pm grant ${applicationId} android.permission.ACCESS_FINE_LOCATION".execute()
}
}
}
}
Y este es el comando para ejecutar la tarea: gradle grantDebugPermissions
Puedes otorgar y revocar permisos usando:
adb shell pm grant com.package.myapp android.permission.<PERMISSION>
adb shell pm revoke com.package.myapp android.permission.<PERMISSION>
Para utilizar las pruebas de instrumentación de Java, llame a este método desde los ejemplos de Google: https://github.com/googlesamples/android-testing/blob/ed62c450e43f859333b3113d44dd59f75971b529/ui/espresso/IntentsBasicSample/app/src/androidTest/java/com/example/android/testing/espresso/BasicSample/DialerActivityTest.java#L94
Puedes usar developer.android.com/reference/android/support/test/rule/… . Esta regla otorgará todos los permisos de tiempo de ejecución solicitados para todos los métodos de prueba en esa clase de prueba.
@Rule
public GrantPermissionRule mRuntimePermissionRule
= GrantPermissionRule.grant(Manifest.permission.READ_PHONE_STATE);
Si está utilizando la última biblioteca ''com.android.support.test.espresso: espresso-core: 3.0.1'' para espresso, esto se puede hacer en una sola línea de código. Todo lo que necesita hacer es agregar una regla en la clase Prueba y seguir agregando los permisos que necesita como parámetros de función para otorgar la función. Vea abajo:
@Rule
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule .grant(Manifest.permission.READ_PHONE_STATE, Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.BLUETOOTH,Manifest.permission.RECORD_AUDIO);
Solo unos pocos ACTUALIZACIONES menores al fragmento anterior (apoyos a riwnodennyk), que funcionó muy bien para mí al compilar contra el SDK 24 y con la versión de herramientas 24.0.0:
import com.android.ddmlib.AndroidDebugBridge
import com.android.ddmlib.IShellOutputReceiver
import com.android.ddmlib.IDevice
import java.util.concurrent.TimeUnit
android.applicationVariants.all { variant ->
def applicationId = [variant.mergedFlavor.applicationId, variant.buildType.applicationIdSuffix].findAll().join()
def grantPermissionsTask = tasks.create("grant${variant.name.capitalize()}Permissions") << {
if (!project.hasProperty(''permissions'')) {
throw new GradleException("Please add the comma-separated command line parameter, for example -Ppermissions=android.permission.WRITE_EXTERNAL_STORAGE")
}
AndroidDebugBridge adb = initAdb(android.getAdbExe().toString())
grantPermissionsOnAllConnectedDevice(adb, applicationId, project.properties[''permissions''].split('',''))
}
grantPermissionsTask.description = "Grants permissions for ${variant.name.capitalize()}."
grantPermissionsTask.dependsOn "install${variant.name.capitalize()}"
}
public static Object grantPermissionsOnAllConnectedDevice(AndroidDebugBridge adb, String applicationId, String[] permissionNames) {
return adb.getDevices().each {
device ->
int apiLevel = Integer.parseInt(device.getProperty(IDevice.PROP_BUILD_API_LEVEL))
if (0 < apiLevel && apiLevel < 23) {
println "/nSkipping granting permissions for " + device.serialNumber + " because has API level " + device.apiLevel + " < 23"
return
}
println "/nGranting permissions for " + applicationId + " on " + device.serialNumber
permissionNames.each {
permissionName ->
def shellGrantCommand = "pm grant " + applicationId + " " + permissionName
println(shellGrantCommand)
device.executeShellCommand(shellGrantCommand, new IShellOutputReceiver() {
@Override
void addOutput(byte[] data, int offset, int length) {
println new String(data[offset..(offset + length - 1)] as byte[])
}
@Override
void flush() {
}
@Override
boolean isCancelled() {
return false
}
})
}
}
}
public static AndroidDebugBridge initAdb(String path) {
AndroidDebugBridge.initIfNeeded(false)
AndroidDebugBridge adb = AndroidDebugBridge.createBridge(path, false)
waitForAdb(adb, 15000)
return adb
}
private static void waitForAdb(AndroidDebugBridge adb, long timeOutMs) {
long sleepTimeMs = TimeUnit.SECONDS.toMillis(1);
while (!adb.hasInitialDeviceList() && timeOutMs > 0) {
try {
Thread.sleep(sleepTimeMs);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
timeOutMs -= sleepTimeMs;
}
if (timeOutMs <= 0 && !adb.hasInitialDeviceList()) {
throw new RuntimeException("Timeout getting device list.", null);
}
}
¡ACTUALIZAR! Ahora puedes usar developer.android.com/reference/android/support/test/rule/…
Es más apropiado de usar que las reglas personalizadas.
Respuesta obsoleta:
Puede agregar una regla de prueba para reutilizar el código y agregar más flexibilidad:
/**
* This rule adds selected permissions to test app
*/
public class PermissionsRule implements TestRule {
private final String[] permissions;
public PermissionsRule(String[] permissions) {
this.permissions = permissions;
}
@Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
allowPermissions();
base.evaluate();
revokePermissions();
}
};
}
private void allowPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (String permission : permissions) {
InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
"pm grant " + InstrumentationRegistry.getTargetContext().getPackageName()
+ " " + permission);
}
}
}
private void revokePermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (String permission : permissions) {
InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
"pm revoke " + InstrumentationRegistry.getTargetContext().getPackageName()
+ " " + permission);
}
}
}
}
Después de eso puedes usar esta regla en tus clases de prueba:
@Rule
public final PermissionsRule permissionsRule = new PermissionsRule(
new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS});
Tenga en cuenta:
- La regla no afecta a los métodos @Before porque todas las reglas se ejecutan después de eso
- executeShellCommand es asíncrono y si necesita permisos aceptados justo después de que comenzó la prueba, considere agregar algún retraso
android.support.test.uiautomator.UiDevice mDevice;
@Before
public void setUp() throws Exception {
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
}
@Test
public void testMainActivityScreenshots() {
allowPermissionsIfNeeded();//allowPermissions on Activity
}
private void allowPermissionsIfNeeded() {
if (Build.VERSION.SDK_INT >= 23) {
UiObject allowPermissions = mDevice.findObject(
new UiSelector().className("android.widget.Button")
.resourceId("com.android.packageinstaller:id/permission_allow_button"));// get allow_button Button by id , because on another device languages it is not "Allow"
if (allowPermissions.exists()) {
try {
allowPermissions.click();
allowPermissionsIfNeeded();//allow second Permission
} catch (UiObjectNotFoundException e) {
Timber.e(e, "There is no permissions dialog to interact with ");
}
}
}
}