How to manage Runtime permissions android marshmallow espresso tests

后端 未结 12 930
孤独总比滥情好
孤独总比滥情好 2020-12-05 02:33

I\'m using espresso for testing but sometimes I try to get an image form external storage and with marshmallow I need a Runtime permission otherwise there will be an Excepti

12条回答
  •  情话喂你
    2020-12-05 03:07

    Just a few minor UPDATEs to the above snippet ( props to riwnodennyk ) -- which worked great for me when building against SDK 24 and with tools version 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);
        }
    }
    

提交回复
热议问题