英文:
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 > 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("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, "list are empty", 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("Demo Excel Sheet");
//Now column and row
Row row = sheet.createRow(0);
cell = row.createCell(0);
cell.setCellValue("Person Name");
cell = row.createCell(1);
cell.setCellValue("Phone Number");
cell = row.createCell(2);
cell.setCellValue("Email Address");
//column width
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.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 = "Import 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();
}
// 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(), "Excel Created in " + path, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Not OK", 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.<init>(FileOutputStream.java:236)
at java.io.FileOutputStream.<init>(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("yyyy-MMM-dd_HH-mm-ss", Locale.getDefault())
val formattedDate = timeZoneDate.format( Date())
val workbook = XSSFWorkbook()
val workSheet = workbook.createSheet("MyDeals_$formattedDate")
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 = "data_$formattedDate.xlsx"
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 ->
run {
if (file.name.endsWith(".xlsx")) {
file.deleteOnExit()
}
}
}
val exportFile = File(appPath, fileName)
val sharingIntent = Intent(Intent.ACTION_SEND)
val fileUri =
FileProvider.getUriForFile(//
activity.applicationContext!!,
activity.packageName + ".fileProvider",
exportFile
);
VERY IMPORTANT ".fileProvider"
must match the case with others:
Manifest:
<application
android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyAppTheme"
tools:targetApi="33">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="my.package.with.myid.fileProvider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_path"/>
</provider>
<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:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path
name="files"
path="." />
</paths>
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 = "*/*"
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
As testing I am sending the .xlsx file via Bluetooth to Desktop PC ( Windowws 10) and checking there the data + formatting, and is working!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论