请求在Android 13文件系统上获得写入权限的方法

huangapple go评论81阅读模式
英文:

How to request write permission on the file system Android 13

问题

Here is the translated content from your text:

我正在将我的 Android 应用定向为 Android 13 (API 33)。

我已从列表生成了一个 Excel 文件并保存了它,但它不能在 API 33 上保存,但在 Android 33 以下可以保存得很好。

> 如果需要,已使用以下库
>
>     implementation 'org.apache.poi:poi:4.0.0'
>     implementation 'org.apache.poi:poi-ooxml:4.0.0'

> 清单权限
>
>     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
>     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

检查权限

private void checkPermission() {
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
        if (getApplicationContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
            String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
            requestPermissions(permissions, 1);
        } else {
            importData();
        }
    } else {
        importData();
    }
}

创建 Excel 文件和存储

private void importData() {
    // 从编辑文本获取数据

    try {
        userList.add(new SheetModel("kawcher", "0181238383", "nmkawcher112@gmail.com"));
        userList.add(new SheetModel("shuvo", "0171238383", "demo1@gmail.com"));
        userList.add(new SheetModel("hasan", "0161238383", "demo2@gmail.com"));
        userList.add(new SheetModel("habib", "0151238383", "demo3@gmail.com"));
        userList.add(new SheetModel("selim", "0131238383", "demo4@gmail.com"));
        userList.add(new SheetModel("tayeb", "0121238383", "demo5@gmail.com"));
        userList.add(new SheetModel("abul kalam", "0191238383", "demo6@gmail.com"));
        userList.add(new SheetModel("Kamal", "0101238383", "demo7@gmail.com"));

    } catch (Exception e) {
        e.printStackTrace();
    }

    if (userList.size() > 0) {
        createXlFile();
    } else {
        Toast.makeText(this, "列表为空", Toast.LENGTH_SHORT).show();
    }
}

private void createXlFile() {

    // File filePath = new File(Environment.getExternalStorageDirectory() + "/Demo.xls");
    Workbook wb = new HSSFWorkbook();

    Cell cell = null;

    Sheet sheet = null;
    sheet = wb.createSheet("演示 Excel 表");
    // 现在的列和行
    Row row = sheet.createRow(0);

    cell = row.createCell(0);
    cell.setCellValue("个人姓名");

    cell = row.createCell(1);
    cell.setCellValue("电话号码");

    cell = row.createCell(2);
    cell.setCellValue("电子邮件地址");

    // 列宽
    sheet.setColumnWidth(0, (20 * 200));
    sheet.setColumnWidth(1, (30 * 200));
    sheet.setColumnWidth(2, (30 * 200));

    for (int i = 0; i < userList.size(); i++) {
        Row row1 = sheet.createRow(i + 1);

        cell = row1.createCell(0);
        cell.setCellValue(userList.get(i).getName());

        cell = row1.createCell(1);
        cell.setCellValue((userList.get(i).getPhoneNo()));

        cell = row1.createCell(2);
        cell.setCellValue(userList.get(i).getEmail());

        sheet.setColumnWidth(0, (20 * 200));
        sheet.setColumnWidth(1, (30 * 200));
        sheet.setColumnWidth(2, (30 * 200));
    }
    String folderName = "导入 Excel";
    String fileName = folderName + System.currentTimeMillis() + ".xls";
    String path = Environment.getExternalStorageDirectory() + File.separator + folderName + File.separator + fileName;

    File file = new File(Environment.getExternalStorageDirectory() + File.separator + folderName);
    if (!file.exists()) {
        file.mkdirs();
    }

    FileOutputStream outputStream = null;

    try {
        //
        outputStream = new FileOutputStream(path);
        wb.write(outputStream);
        // ShareViaEmail(file.getParentFile().getName(),file.getName());
        Toast.makeText(getApplicationContext(), "Excel 已创建在 " + path, Toast.LENGTH_SHORT).show();
    } catch (IOException e) {
        e.printStackTrace();

        Toast.makeText(getApplicationContext(), "不正常", Toast.LENGTH_LONG).show();
        try {
            outputStream.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

错误日志:

/System.err: java.io.FileNotFoundException: /storage/emulated/0/Import Excel/Import Excel1681376608447.xls: 打开失败: ENOENT(没有该文件或目录)
...

Please note that some parts of the code are still in English as they contain code elements and variable names.

英文:

I am targeting my Android app for Android 13 (API 33)

I have generated an Excel file from my list and saved it but it doesn't save in API 33 but less than API Android 33 save very well.

> If needed, these libraries have been used
>
> implementation 'org.apache.poi:poi:4.0.0'
> implementation 'org.apache.poi:poi-ooxml:4.0.0'
>

> Manifest permission
>
> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

Check Permission

private void checkPermission() {
    if (Build.VERSION.SDK_INT &gt; Build.VERSION_CODES.M) {
        if (getApplicationContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
            String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
            requestPermissions(permissions, 1);
        } else {
            importData();
        }
    } else {
        importData();
    }

}

make excel files and storage

    private void importData() {
        //get data from edit text

        try {
            userList.add(new SheetModel(&quot;kawcher&quot;, &quot;0181238383&quot;, &quot;nmkawcher112@gmail.com&quot;));
            userList.add(new SheetModel(&quot;shuvo&quot;, &quot;0171238383&quot;, &quot;demo1@gmail.com&quot;));
            userList.add(new SheetModel(&quot;hasan&quot;, &quot;0161238383&quot;, &quot;demo2@gmail.com&quot;));
            userList.add(new SheetModel(&quot;habib&quot;, &quot;0151238383&quot;, &quot;demo3@gmail.com&quot;));
            userList.add(new SheetModel(&quot;selim&quot;, &quot;0131238383&quot;, &quot;demo4@gmail.com&quot;));
            userList.add(new SheetModel(&quot;tayeb&quot;, &quot;0121238383&quot;, &quot;demo5@gmail.com&quot;));
            userList.add(new SheetModel(&quot;abul kalam&quot;, &quot;0191238383&quot;, &quot;demo6@gmail.com&quot;));
            userList.add(new SheetModel(&quot;Kamal&quot;, &quot;0101238383&quot;, &quot;demo7@gmail.com&quot;));

        }catch (Exception e){e.printStackTrace();}

        if (userList.size() &gt; 0) {
            createXlFile();


        } else {
            Toast.makeText(this, &quot;list are empty&quot;, Toast.LENGTH_SHORT).show();
        }
    }

    private void createXlFile() {

        // File filePath = new File(Environment.getExternalStorageDirectory() + &quot;/Demo.xls&quot;);
        Workbook wb = new HSSFWorkbook();


        Cell cell = null;

        Sheet sheet = null;
        sheet = wb.createSheet(&quot;Demo Excel Sheet&quot;);
        //Now column and row
        Row row = sheet.createRow(0);

        cell = row.createCell(0);
        cell.setCellValue(&quot;Person Name&quot;);


        cell = row.createCell(1);
        cell.setCellValue(&quot;Phone Number&quot;);


        cell = row.createCell(2);
        cell.setCellValue(&quot;Email Address&quot;);


        //column width
        sheet.setColumnWidth(0, (20 * 200));
        sheet.setColumnWidth(1, (30 * 200));
        sheet.setColumnWidth(2, (30 * 200));


        for (int i = 0; i &lt; userList.size(); i++) {
            Row row1 = sheet.createRow(i + 1);

            cell = row1.createCell(0);
            cell.setCellValue(userList.get(i).getName());

            cell = row1.createCell(1);
            cell.setCellValue((userList.get(i).getPhoneNo()));
            //  cell.setCellStyle(cellStyle);

            cell = row1.createCell(2);
            cell.setCellValue(userList.get(i).getEmail());


            sheet.setColumnWidth(0, (20 * 200));
            sheet.setColumnWidth(1, (30 * 200));
            sheet.setColumnWidth(2, (30 * 200));

        }
        String folderName = &quot;Import Excel&quot;;
        String fileName = folderName + System.currentTimeMillis() + &quot;.xls&quot;;
        String path = Environment.getExternalStorageDirectory() + File.separator + folderName + File.separator + fileName;

        File file = new File(Environment.getExternalStorageDirectory() + File.separator + folderName);
        if (!file.exists()) {
            file.mkdirs();
        }
//         file.deleteOnExit();

        FileOutputStream outputStream = null;

        try {

            //
            outputStream = new FileOutputStream(path);
//            outputStream = new FileOutputStream(new File(getFilesDir()., path));
            wb.write(outputStream);
            // ShareViaEmail(file.getParentFile().getName(),file.getName());
            Toast.makeText(getApplicationContext(), &quot;Excel Created in &quot; + path, Toast.LENGTH_SHORT).show();
        } catch (IOException e) {
            e.printStackTrace();

            Toast.makeText(getApplicationContext(), &quot;Not OK&quot;, Toast.LENGTH_LONG).show();
            try {
                outputStream.close();
            } catch (Exception ex) {
                ex.printStackTrace();

            }
        }

    }

Error logcat:

     /System.err: java.io.FileNotFoundException: /storage/emulated/0/Import Excel/Import Excel1681376608447.xls: open
 failed: ENOENT (No such file or directory)
             at libcore.io.IoBridge.open(IoBridge.java:574)
             at java.io.FileOutputStream.&lt;init&gt;(FileOutputStream.java:236)
             at java.io.FileOutputStream.&lt;init&gt;(FileOutputStream.java:125)
             at com.roomack.amlaak.view.activity.MainActivity.createXlFile(MainActivity.java:1125)
             at com.roomack.amlaak.view.activity.MainActivity.importData(MainActivity.java:1051)
             at com.roomack.amlaak.view.activity.MainActivity.checkPermission(MainActivity.java:1020)
             at com.roomack.amlaak.view.activity.MainActivity.access$300(MainActivity.java:100)
             at com.roomack.amlaak.view.activity.MainActivity$18.onClick(MainActivity.java:821)
             at android.view.View.performClick(View.java:7560)
             at android.view.View.performClickInternal(View.java:7533)
             at ndroid.view.View.-$$Nest$mperformClickInternal(Unknown Source:0)
             at android.view.View$PerformClick.run(View.java:29754)
     W/System.err:     at android.os.Handler.handleCallback(Handler.java:942)
             at android.os.Handler.dispatchMessage(Handler.java:99)
             at android.os.Looper.loopOnce(Looper.java:211)
             at android.os.Looper.loop(Looper.java:300)
             at android.app.ActivityThread.main(ActivityThread.java:8143)
             at java.lang.reflect.Method.invoke(Native Method)
             at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1028)
         Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
             at libcore.io.Linux.open(Native Method)
             at libcore.io.ForwardingOs.open(ForwardingOs.java:563)
             at libcore.io.BlockGuardOs.open(BlockGuardOs.java:274)
             at libcore.io.ForwardingOs.open(ForwardingOs.java:563)
             at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:8019)
             at libcore.io.IoBridge.open(IoBridge.java:560)

答案1

得分: 1

你无法在Android 13设备上请求写入权限。

在所有应用特定目录和外部存储的所有公共目录中,您都自动具有写入权限。

英文:

You cannot request write permission on Android 13 devices.

You automatically have write permission in all app specific directories and all public directories on external storage.

答案2

得分: 0

In HomeFragment.kt中调用如下方式:

binding.btHomeExport.setOnClickListener {
    GlobalScope.launch {
        exportData(requireActivity())
    }
}

Export.kt只是一个从Java实用程序类转换为Kotlin的实用程序类,实际上只是为了移出代码:

object Export {
    suspend fun exportData(activity: Activity) {
        // 其他代码...
    }
}

今天(2023年5月22日),它在Android 33上运行,但明天可能会因Google更改API而不起作用。

英文:

In HomeFragment.kt is called like this:

    binding.btHomeExport.setOnClickListener {
        GlobalScope.launch {
            exportData(requireActivity())
        }
    }

The Export.kt it is just a Java utility class converted to Kotlin, practically just to move out the code:

object Export {
suspend fun exportData(activity: Activity) {

    try {
        // read again from file?

        val listMyDealWithMyClient = doReadFromFile(activity)

        val timeZoneDate = SimpleDateFormat(&quot;yyyy-MMM-dd_HH-mm-ss&quot;, Locale.getDefault())
        val formattedDate = timeZoneDate.format( Date())

        val workbook = XSSFWorkbook()
        val workSheet = workbook.createSheet(&quot;MyDeals_$formattedDate&quot;)
        val colorMap = workbook.stylesSource.indexedColors

        val cellStyleHeader = workbook.createCellStyle()
        cellStyleHeader.fillForegroundColor = IndexedColors.AQUA.getIndex()
        cellStyleHeader.fillPattern = FillPatternType.SOLID_FOREGROUND
        cellStyleHeader.font.bold = true
        cellStyleHeader.verticalAlignment = VerticalAlignment.CENTER
        cellStyleHeader.alignment = HorizontalAlignment.CENTER
        cellStyleHeader.setRightBorderColor( XSSFColor(byteArrayOf(0, 0, 0), colorMap))
        cellStyleHeader.borderRight = BorderStyle.THIN


        val row0 = workSheet.createRow(0)
        row0.height = 800

more code here, which are data procesing ...

        // save workbook to file:
        val fileName = &quot;data_$formattedDate.xlsx&quot;
        val fos: FileOutputStream =
            activity.openFileOutput(fileName, Context.MODE_PRIVATE)!!

        workbook.write(fos)
        workbook.close()

        withContext(Dispatchers.IO) {
            fos.flush()
            fos.close();
        };

        //need: fos.path, but it is private!

        val appPath = activity.application?.filesDir?.absolutePath
        // delete old .xlsx files
        val dir = appPath?.let { File(it) }
        dir?.listFiles()!!.forEach { file -&gt;
            run {
                if (file.name.endsWith(&quot;.xlsx&quot;)) {
                    file.deleteOnExit()
                }
            }
        }

        val exportFile = File(appPath, fileName)


        val sharingIntent = Intent(Intent.ACTION_SEND)

        val fileUri =
            FileProvider.getUriForFile(//
                activity.applicationContext!!,
                activity.packageName + &quot;.fileProvider&quot;,
                exportFile
            );

VERY IMPORTANT &quot;.fileProvider&quot; must match the case with others:
Manifest:

&lt;application
    android:allowBackup=&quot;false&quot;
    android:dataExtractionRules=&quot;@xml/data_extraction_rules&quot;
    android:fullBackupContent=&quot;@xml/backup_rules&quot;
    android:icon=&quot;@mipmap/ic_launcher&quot;
    android:label=&quot;@string/app_name&quot;
    android:roundIcon=&quot;@mipmap/ic_launcher_round&quot;
    android:supportsRtl=&quot;true&quot;
    android:theme=&quot;@style/Theme.MyAppTheme&quot;
    tools:targetApi=&quot;33&quot;&gt;



    &lt;provider
        android:name=&quot;androidx.core.content.FileProvider&quot;
        android:authorities=&quot;my.package.with.myid.fileProvider&quot;
        android:grantUriPermissions=&quot;true&quot;
        android:exported=&quot;false&quot;&gt;
        &lt;meta-data
            android:name=&quot;android.support.FILE_PROVIDER_PATHS&quot;
            android:resource=&quot;@xml/file_provider_path&quot;/&gt;
    &lt;/provider&gt;

    &lt;activity
        android:name=

NOT needed Read External, Write External permissions! None needed!

At res/xml create a file file_provider_path.xml

Paste the content:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;paths&gt;
    &lt;files-path
        name=&quot;files&quot;
        path=&quot;.&quot; /&gt;
&lt;/paths&gt;

The file it wil be exported, not sure how it can be accessed by other apps. That's why I do a share / send file and I let the user choose the Intent:

            // add provider
            sharingIntent.type = &quot;*/*&quot;
            sharingIntent.putExtra(Intent.EXTRA_STREAM, fileUri)

            sharingIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION

            activity.startActivity(sharingIntent)


        } catch (ex: Exception) {
            ex.printStackTrace()
            Toast.makeText(activity, ex.message, Toast.LENGTH_LONG).show();
        }
    }
}

This is the final part of the Export.kt

Today (May 22, 2023) it is working with Android 33...tomorrow maybe not -as how Google changes their API...

I don't target other devices, just Android 33 - because it is a utility app for somebody. It were many changes at Androi pre 8, post 8, pre 9 , post 9, pre 10, post 10, pre 11, pre 12, post 12, pre 13, and +13
Spent like 10 days to put the lego pieces together 请求在Android 13文件系统上获得写入权限的方法

As testing I am sending the .xlsx file via Bluetooth to Desktop PC ( Windowws 10) and checking there the data + formatting, and is working!

huangapple
  • 本文由 发表于 2023年4月13日 17:16:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76003739.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定