在AndroidTest中编写外部存储

时间:2018-03-09 17:02:20

标签: java android testing android-permissions android-external-storage

我想为一个应用程序写一个AndroidTest,它涉及写入外部存储,但不知怎的,我无法使它工作。 (在Pixel2,Lg G6,Huawai P8等多种设备上进行测试)

所以我简化了一切,只是为了测试是否可以写入外部存储器。我试用了GrantPermissionRule以及在Granter上写我没有成功。

我可能最终做了太多不必要的事情,所以这就是我所做的:

  1. AndroidStudio
  2. 中创建无活动的新项目
  3. 添加了Manifest的许可
  4. 添加了AndroidManifest uses-permission代码
  5. 写了我自己的PermissionRequester
  6. 写了测试以尝试在/ sdcard / Download中添加一个文件夹并将其删除
  7. 以下是上面编号列表引用的片段

    2

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.company.android.testpermissions">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="com.company.TestPermissions"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" />
    </manifest>
    

    3

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.company.android.testpermissions.test">
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    
    </manifest>
    

    也试过

    <manifest package="com.company.android.testpermissions">...
    

    省略'test'后缀

    4

    public class MyPermissionRequester {
    
        public static final String TAG = MyPermissionRequester.class.getSimpleName();
    
        public static void request(String... permissions) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                UiAutomation auto = InstrumentationRegistry.getInstrumentation().getUiAutomation();
                String cmd = "pm grant " + InstrumentationRegistry.getTargetContext().getPackageName() + " %1$s";
                String cmdTest = "pm grant " + InstrumentationRegistry.getContext().getPackageName() + " %1$s";
                String currCmd;
                for (String perm : permissions) {
                    execute(String.format(cmd, perm), auto);
                    execute(String.format(cmdTest, perm), auto);
                }
            }
            GrantPermissionRule.grant(permissions);
        }
    
        private static void execute(String currCmd, UiAutomation auto){
            Log.d(TAG, "exec cmd: " + currCmd);
            auto.executeShellCommand(currCmd);
        }
    }
    

    5

    @RunWith(AndroidJUnit4.class)
    public class ExampleInstrumentedTest {
        @Test
        public void sdcardTest(){
    
            //check sdcard availability 
            Assert.assertEquals("Media is not mounted!", Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED);
           //get and check Permissions
    MyPermissionRequester.request(Manifest.permission.WRITE_EXTERNAL_STORAGE);
            int grantResult = ActivityCompat.checkSelfPermission(InstrumentationRegistry.getTargetContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
            Assert.assertEquals(PackageManager.PERMISSION_GRANTED, grantResult);
            grantResult = ActivityCompat.checkSelfPermission(InstrumentationRegistry.getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
            Assert.assertEquals(PackageManager.PERMISSION_GRANTED, grantResult);
    
            //finally try to create folder
            File f = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "CompanyTest");
            if (!f.exists()){
                boolean mkdir = f.mkdirs();
                Assert.assertTrue("Folder '"+f.getAbsolutePath() + "' not Present!", mkdir);
            }
            boolean delete = f.delete();
            Assert.assertTrue("Folder '"+f.getAbsolutePath() + "' is Present!", delete);
        }
    }
    

    测试的结果是:

      

    junit.framework.AssertionFailedError:文件夹   '/ storage / emulated / 0 /下载/ CompanyTest'不存在!在

         

    junit.framework.Assert.fail(Assert.java:50)

         

    junit.framework.Assert.assertTrue(Assert.java:20)

         

    com.company.android.testpermissions.ExampleInstrumentedTest.sdcardTest(ExampleInstrumentedTest.java:69)

         

    at java.lang.reflect.Method.invoke(Native Method)at   ...   (省略来自TestRunner的休息)

    我在这里错过了什么或做错了什么?

3 个答案:

答案 0 :(得分:4)

经过多次努力尝试无法解决的问题后,我终于得到了解决方案:

谷歌声称

if your application already requests write access, it will automatically get read access as well.

https://developer.android.com/about/versions/android-4.1.html#Permissions

或在WriteExternalStorage文档中:

Note: If your app uses the WRITE_EXTERNAL_STORAGE permission, then it implicitly has permission to read the external storage as well.

https://developer.android.com/training/data-storage/files.html#WriteExternalStorage

或在清单Permissions中:

Any app that declares the WRITE_EXTERNAL_STORAGE permission is implicitly granted this permission.

https://developer.android.com/reference/android/Manifest.permission.html#READ_EXTERNAL_STORAGE

除了它没有!

如果我明确地将READ_EXTERNAL_STORAGE添加到我的清单以及在运行时请求它,它就会像我以前那样工作。

所以3.必须添加

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.company.android.testpermissions.test">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
</manifest>

并且测试应该如下所示:

@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
    @Test
    public void sdcardTest(){

        //check sdcard availability 
        Assert.assertEquals("Media is not mounted!", Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED);
       //get and check Permissions
MyPermissionRequester.request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE);
        int grantResult = ActivityCompat.checkSelfPermission(InstrumentationRegistry.getTargetContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
        Assert.assertEquals(PackageManager.PERMISSION_GRANTED, grantResult);
        grantResult = ActivityCompat.checkSelfPermission(InstrumentationRegistry.getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
        Assert.assertEquals(PackageManager.PERMISSION_GRANTED, grantResult);

        //finally try to create folder
        File f = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "CompanyTest");
        if (!f.exists()){
            boolean mkdir = f.mkdirs();
            Assert.assertTrue("Folder '"+f.getAbsolutePath() + "' not Present!", mkdir);
        }
        boolean delete = f.delete();
        Assert.assertTrue("Folder '"+f.getAbsolutePath() + "' is Present!", delete);
    }
}

一切正常。

唯一的问题是,自Android 8.1以来,这是否是预期的行为

答案 1 :(得分:1)

就像我在评论中所述,

我唯一能想到的是,在你引用的两个例子中,他们似乎都在引用旧版本的Android(看起来他们正在引用Android 4.1)。这是一个明确声明用户必须在Android 6.0之后明确批准不属于应用程序“沙箱”的每个权限的链接:

https://developer.android.com/training/permissions/requesting.html

此外,他们在我上面提供的链接中明确说明您必须在清单中包含READ和WRITE。然后,您可以使用运行时权限,这将涵盖两者,但前提是您在清单中包含这两者。 (在“处理权限请求响应”部分下)

答案 2 :(得分:0)

从Android 6.0开始,您需要手动授予运行时权限以运行androidTest

adb shell pm grant <pkg_name> android.permission.READ_EXTERNAL_STORAGE adb shell pm grant <pkg_name> android.permission.WRITE_EXTERNAL_STORAGE 您可以通过以下方式验证权限 adb shell dumpsys package <pkg_name> AndroidManifest.xml仅请求这些权限,而在安装androidTest APK时默认不授予这些权限。