【问题标题】:Write External Storage in AndroidTest在 AndroidTest 中编写外部存储
【发布时间】:2018-08-18 07:34:10
【问题描述】:

我想为一个涉及写入外部存储的应用程序写一个AndroidTest,但不知何故我无法让它工作。 (在Pixel2、LG G6、华为P8等多台设备上测试)

所以我简化了一切,只是为了测试是否可以写入外部存储。我尝试了GrantPermissionRule 并在Granter 上写了我的文章,但完全没有成功。

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

  1. AndroidStudio 中创建没有活动的新项目
  2. 为清单添加了权限
  3. 添加了AndroidManifestuses-permission标签
  4. 写了我自己的PermissionRequester
  5. 编写测试尝试在/sdcard/Download中添加一个文件夹并删除它

以下是上面编号列表引用的sn-ps

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">...

省略“测试”后缀

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/Download/CompanyTest' 不存在!在

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

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

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

在 java.lang.reflect.Method.invoke(Native Method) 在 ... (省略了来自 TestRunner 的其余部分)

我在这里遗漏了什么或做错了什么?

【问题讨论】:

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


    【解决方案1】:

    在尝试了很多无效的东西之后,我终于找到了解决方案:

    Google 声称

    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

    或在清单权限中:

    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 以来的预期行为

    【讨论】:

    • 你的意思是为什么这是自 Android 8.1 以来的预期行为?从 Android 6.0+ 开始就需要这样做
    • @cjnash 你的意思是说,如果你从 Android 6 开始已经授予 WRITE_EXTERNAL_STORAGE,还需要请求 READ_EXTERNAL_STORAGE?你有官方消息来源吗?我的意思是我提供了至少 2 个示例,文档告诉您,如果您有 WRITE,则隐式授予 READ
    • 我唯一能想到的是,在您引用的两个示例中,它们似乎都引用了旧版本的 Android(看起来它们引用了 Android 4.1)。这是一个明确指出用户必须明确批准在 Android 6.0 之后不属于应用程序“沙箱”的每个权限的链接:developer.android.com/training/permissions/requesting.html
    • 此外,他们在我上面提供的链接中明确指出,您必须在清单中同时包含 READWRITE。然后您可以使用运行时权限,这将涵盖两者,但前提是您将两者都包含在清单中。 (在“处理权限请求响应”部分下)
    【解决方案2】:

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

    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 时默认不授予。

    【讨论】:

      【解决方案3】:

      就像我在我的 cmets 中所说的,

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

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

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

      【讨论】:

      • 但我的应用程序以 Andoidoir 6.0 为目标,在运行时不必获得READ_EXTERNAL_STORAGE 权限。仅在清单中添加READ_EXTERNAL_STORAGE 并在运行时获取WRITE_EXTERNAL_STORAGE 就足以让我的应用程序获得许可。并且还如文档developer.android.com/reference/android/… 中所述,当您被授予WRITE_EXTERNAL_STORAGE 权限时,无需获得READ_EXTERNAL_STORAGE 权限。
      • 是的,在运行时您只需要授予一个,只要它针对EXTERNAL_STORAGE,那么READWRITE 就足够了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-28
      • 2013-06-06
      • 1970-01-01
      • 2012-01-09
      • 2012-08-11
      相关资源
      最近更新 更多