$cordovaImagePicker 選擇系統相冊,安裝時已聲明權限。AndroidManifest.xml 聲明僅是安裝時聲明。SecurityException 崩潰。<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
// TypeScript / JavaScript
import { AndroidPermissions } from '@ionic-native/android-permissions/ngx';
constructor(private androidPermissions: AndroidPermissions) {}
async pickImage() {
const permission = this.androidPermissions.PERMISSION.READ_EXTERNAL_STORAGE;
const result = await this.androidPermissions.checkPermission(permission);
if (!result.hasPermission) {
const requestResult = await this.androidPermissions.requestPermission(permission);
if (!requestResult.hasPermission) {
alert('需要存儲權限才能選擇圖片');
return;
}
}
// 權限已授予,調用 ImagePicker
this.imagePicker.getPictures(options).then(...);
}
// Activity/Fragment 中
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
REQUEST_CODE_READ_STORAGE);
} else {
launchImagePicker();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_CODE_READ_STORAGE && grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
launchImagePicker();
} else {
Toast.makeText(this, "權限被拒絕", Toast.LENGTH_SHORT).show();
}
}
PermissionUtil.request(permission, rationale, callback) 統一入口。cordova-plugin-android-permissions 官方維護版。「Manifest 聲明 ≠ 運行時擁有」 —— 動態權限是 Android 6+ 的鐵律,華為等廠商更是嚴格執行者,補上運行時請求,崩潰即刻消失。