在測試cordova開發的安卓APP過程當中,使用$cordovaImagePicker.getPictures(options)獲取相冊照片時,華爲機型老是會閃退。java
config.xml已經添加了權限android
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.CAMERA" />
若是先調用相機$cordovaCamera.getPicture(options)彈出權限申請,賦予權限後再調用$cordovaImagePicker.getPictures(options)就不會閃退。apache
查看了一下調用相機插件cordova-plugin-camera源碼org.apache.cordova.camera.CameraLauncher中的方法callTakePicture,可知其作了權限的檢測,源碼以下:json
/** * Take a picture with the camera. * When an image is captured or the camera view is cancelled, the result is returned * in CordovaActivity.onActivityResult, which forwards the result to this.onActivityResult. * * The image can either be returned as a base64 string or a URI that points to the file. * To display base64 string in an img tag, set the source to: * img.src="data:image/jpeg;base64,"+result; * or to display URI in an img tag * img.src=result; * * @param returnType Set the type of image to return. * @param encodingType Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality) */ public void callTakePicture(int returnType, int encodingType) { boolean saveAlbumPermission = PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE); boolean takePicturePermission = PermissionHelper.hasPermission(this, Manifest.permission.CAMERA); // CB-10120: The CAMERA permission does not need to be requested unless it is declared // in AndroidManifest.xml. This plugin does not declare it, but others may and so we must // check the package info to determine if the permission is present. if (!takePicturePermission) { takePicturePermission = true; try { PackageManager packageManager = this.cordova.getActivity().getPackageManager(); String[] permissionsInPackage = packageManager.getPackageInfo(this.cordova.getActivity().getPackageName(), PackageManager.GET_PERMISSIONS).requestedPermissions; if (permissionsInPackage != null) { for (String permission : permissionsInPackage) { if (permission.equals(Manifest.permission.CAMERA)) { takePicturePermission = false; break; } } } } catch (NameNotFoundException e) { // We are requesting the info for our package, so this should // never be caught } } if (takePicturePermission && saveAlbumPermission) { takePicture(returnType, encodingType); } else if (saveAlbumPermission && !takePicturePermission) { PermissionHelper.requestPermission(this, TAKE_PIC_SEC, Manifest.permission.CAMERA); } else if (!saveAlbumPermission && takePicturePermission) { PermissionHelper.requestPermission(this, TAKE_PIC_SEC, Manifest.permission.READ_EXTERNAL_STORAGE); } else { PermissionHelper.requestPermissions(this, TAKE_PIC_SEC, permissions); } }
而後又查看了一下cordova-plugin-image-picker插件com.synconset.ImagePicker.java的源碼發現方法execute沒有作權限檢測直接執行this.cordova.startActivityForResult((CordovaPlugin) this, intent, 0)方法,而這個方法最終調用的是android.app.Activity.java中的startActivityForResult(intent, requestCode)方法。app
android.app.Activity.java中startActivityForResult方法的源碼:less
/** * Same as calling {@link #startActivityForResult(Intent, int, Bundle)} * with no options. * * @param intent The intent to start. * @param requestCode If >= 0, this code will be returned in * onActivityResult() when the activity exits. * * @throws android.content.ActivityNotFoundException * * @see #startActivity */ public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) { startActivityForResult(intent, requestCode, null); }
能夠看到這個方法加了@RequiresPermission,因此在沒有權限的狀況下直接調用可能會被拒絕。測試
因此須要在調用前申請權限。ui
解決:this
這是com.synconset.ImagePicker.java插件源碼:spa
/** * An Image Picker Plugin for Cordova/PhoneGap. */ package com.synconset; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.PermissionHelper; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import android.Manifest; import android.app.Activity; import android.content.Intent; import android.util.Log; public class ImagePicker extends CordovaPlugin { public static String TAG = "ImagePicker"; private CallbackContext callbackContext; private JSONObject params; public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException { this.callbackContext = callbackContext; this.params = args.getJSONObject(0); if (action.equals("getPictures")) { Intent intent = new Intent(cordova.getActivity(), MultiImageChooserActivity.class); int max = 20; int desiredWidth = 0; int desiredHeight = 0; int quality = 100; if (this.params.has("maximumImagesCount")) { max = this.params.getInt("maximumImagesCount"); } if (this.params.has("width")) { desiredWidth = this.params.getInt("width"); } if (this.params.has("height")) { desiredHeight = this.params.getInt("height"); } if (this.params.has("quality")) { quality = this.params.getInt("quality"); } intent.putExtra("MAX_IMAGES", max); intent.putExtra("WIDTH", desiredWidth); intent.putExtra("HEIGHT", desiredHeight); intent.putExtra("QUALITY", quality);
if (this.cordova != null) { this.cordova.startActivityForResult((CordovaPlugin) this, intent, 0); } } return true; } public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK && data != null) { ArrayList<String> fileNames = data.getStringArrayListExtra("MULTIPLEFILENAMES"); JSONArray res = new JSONArray(fileNames); this.callbackContext.success(res); } else if (resultCode == Activity.RESULT_CANCELED && data != null) { String error = data.getStringExtra("ERRORMESSAGE"); this.callbackContext.error(error); } else if (resultCode == Activity.RESULT_CANCELED) { JSONArray res = new JSONArray(); this.callbackContext.success(res); } else { this.callbackContext.error("No images selected"); } } }
這是我修改後添加了權限申請的代碼:
/** * An Image Picker Plugin for Cordova/PhoneGap. */ package com.synconset; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.PermissionHelper; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import android.Manifest; import android.app.Activity; import android.content.Intent; import android.util.Log; public class ImagePicker extends CordovaPlugin { public static String TAG = "ImagePicker"; private CallbackContext callbackContext; private JSONObject params; public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException { this.callbackContext = callbackContext; this.params = args.getJSONObject(0); if (action.equals("getPictures")) { Intent intent = new Intent(cordova.getActivity(), MultiImageChooserActivity.class); int max = 20; int desiredWidth = 0; int desiredHeight = 0; int quality = 100; if (this.params.has("maximumImagesCount")) { max = this.params.getInt("maximumImagesCount"); } if (this.params.has("width")) { desiredWidth = this.params.getInt("width"); } if (this.params.has("height")) { desiredHeight = this.params.getInt("height"); } if (this.params.has("quality")) { quality = this.params.getInt("quality"); } intent.putExtra("MAX_IMAGES", max); intent.putExtra("WIDTH", desiredWidth); intent.putExtra("HEIGHT", desiredHeight); intent.putExtra("QUALITY", quality); //添加權限申請 boolean saveAlbumPermission = PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE); if(!saveAlbumPermission){ PermissionHelper.requestPermission(this, 0, Manifest.permission.READ_EXTERNAL_STORAGE); }else{ if (this.cordova != null) { this.cordova.startActivityForResult((CordovaPlugin) this, intent, 0); } } } return true; } public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK && data != null) { ArrayList<String> fileNames = data.getStringArrayListExtra("MULTIPLEFILENAMES"); JSONArray res = new JSONArray(fileNames); this.callbackContext.success(res); } else if (resultCode == Activity.RESULT_CANCELED && data != null) { String error = data.getStringExtra("ERRORMESSAGE"); this.callbackContext.error(error); } else if (resultCode == Activity.RESULT_CANCELED) { JSONArray res = new JSONArray(); this.callbackContext.success(res); } else { this.callbackContext.error("No images selected"); } } }
這樣問題就解決了。