使用相机插件拍摄新照片时,PhoneGap 应用程序崩溃

Posted

技术标签:

【中文标题】使用相机插件拍摄新照片时,PhoneGap 应用程序崩溃【英文标题】:PhoneGap App Crash when take a new photo with Camera Plugin 【发布时间】:2015-06-03 10:00:05 【问题描述】:

我正在使用 cordova/phonegap 开发一个移动应用程序,并且我已经安装了相机插件。我可以打开相机并单击图像,但在该应用程序崩溃之后。这是崩溃日志:

    java.lang.RuntimeException: Failure delivering result ResultInfowho=null, request=34, result=-1, data=null to activity com.phonegap.helloworld/com.phonegap.helloworld.CordovaApp: java.lang.IllegalArgumentException: filename cannot be null
    E/androidRuntime(22226):    at android.app.ActivityThread.deliverResults(ActivityThread.java:3510)
    E/AndroidRuntime(22226):    at android.app.ActivityThread.handleSendResult(ActivityThread.java:3553)
    E/AndroidRuntime(22226):    at android.app.ActivityThread.access$1200(ActivityThread.java:165)
    E/AndroidRuntime(22226):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1374)
    E/AndroidRuntime(22226):    at android.os.Handler.dispatchMessage(Handler.java:99)
    E/AndroidRuntime(22226):    at android.os.Looper.loop(Looper.java:176)
    E/AndroidRuntime(22226):    at android.app.ActivityThread.main(ActivityThread.java:5455)
    E/AndroidRuntime(22226):    at java.lang.reflect.Method.invokeNative(Native Method)
    E/AndroidRuntime(22226):    at java.lang.reflect.Method.invoke(Method.java:525)
    E/AndroidRuntime(22226):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
    E/AndroidRuntime(22226):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
    E/AndroidRuntime(22226):    at dalvik.system.NativeStart.main(Native Method)
    E/AndroidRuntime(22226): Caused by: java.lang.IllegalArgumentException: filename cannot be null
    E/AndroidRuntime(22226):    at android.media.ExifInterface.<init>(ExifInterface.java:121)
    E/AndroidRuntime(22226):    at org.apache.cordova.camera.ExifHelper.createOutFile(ExifHelper.java:66)
    E/AndroidRuntime(22226):    at org.apache.cordova.camera.CameraLauncher.processResultFromCamera(CameraLauncher.java:430)
    E/AndroidRuntime(22226):    at org.apache.cordova.camera.CameraLauncher.onActivityResult(CameraLauncher.java:610)
    E/AndroidRuntime(22226):    at org.apache.cordova.CordovaActivity.onActivityResult(CordovaActivity.java:784)
    E/AndroidRuntime(22226):    at android.app.Activity.dispatchActivityResult(Activity.java:5563)
    E/AndroidRuntime(22226):    at android.app.ActivityThread.deliverResults(ActivityThread.java:3506)
    E/AndroidRuntime(22226):    ... 11 more

我用来打开相机的代码是:

   var pictureSource; // picture source
var destinationType; // sets the format of returned value
document.addEventListener("deviceready", onDeviceReady, false);

function onDeviceReady() 
  // alert("ready-----")
  pictureSource = navigator.camera.PictureSourceType;
  destinationType = navigator.camera.DestinationType;


function capturePhoto() 
  alert(navigator.camera);
  navigator.camera.getPicture(onPhotoDataSuccess, onFail, 
    quality: 20,
    destinationType: destinationType.FILE_URI,
    targetWidth: 200,
    targetHeight: 200,
    saveToPhotoAlbum: true,
    sourceType: pictureSource.CAMERA
  );


function onPhotoDataSuccess(imageURI) 
  // alert("success--");
  var smallImage = document.getElementById('smallImage');
  smallImage.style.display = 'block';
  smallImage.src = imageURI;
  // smallImage.src = "data:image/jpeg;base64," + imageData;


function onFail(message) 
  alert('Failed because: ' + message);

该错误已登录Apache Cordova。

求救!!!

【问题讨论】:

您的示例代码与Phonegap's 文档中的相同。它也类似于Cordova's 文档,唯一的区别是这一行:destinationType: Camera.DestinationType.FILE_URI, sourceType: Camera.pictureSource.CAMERA 在选项对象中。你试过那些吗?您使用的是哪个版本的 cordova 或 phonegap? 【参考方案1】:

尝试用这个替换你的 capturePhoto() 函数(这是我自己的应用程序中的工作代码):

function capturePhoto() 
    var options = 
        quality: 75,
        destinationType: Camera.DestinationType.FILE_URI,
        sourceType: Camera.PictureSourceType.CAMERA,
        mediaType: Camera.MediaType.CAMERA,
        encodingType: Camera.EncodingType.JPEG,
        targetWidth: 200,
        targetHeight: 200,
        saveToPhotoAlbum: true
    ;
    navigator.camera.getPicture(onPhotoDataSuccess, onFail, options);

【讨论】:

我在我的安卓设备上遇到了类似的问题,结果我的编码类型设置为 PNG。将其更改为 JPEG 为我解决了这个问题 @Mike Dailor:你救了我的命。我遇到了在 android 11 上运行的 ionic v1 应用程序的问题。您的配置解决了我的问题。你是最棒的。非常感谢。【参考方案2】:

请更改您的目的地类型:

destinationType: destinationType.FILE_URI

destinationType: Camera.DestinationType.FILE_URI

如果您需要它作为 base64 编码图像,则将目标类型更改为:

destinationType: Camera.DestinationType.DATA_URL

还要确保您已在清单文件中添加写入外部存储权限。

【讨论】:

我需要文件中的图像而不是二进制字符串。 您是否更改了目的地类型?使用destinationType:Camera.DestinationType.FILE_URI,您将获得图像的文件位置。 也许你可以删除目标高度和目标宽度参数,试一试我的也是这样。【参考方案3】:

插件将空指针传递给ExifInterface 导致异常,这在旧插件中不会发生。

尝试应用以下修复,您也可以报告设备品牌,型号和android版本吗?

https://issues.apache.org/jira/browse/CB-9446

diff --git a/src/android/ExifHelper.java b/src/android/ExifHelper.java
index 5160a2f..0af0fcd 100644
--- a/src/android/ExifHelper.java
+++ b/src/android/ExifHelper.java
@@ -53,7 +53,11 @@ public class ExifHelper 
  * @throws IOException
  */
 public void createInFile(String filePath) throws IOException 
-        this.inFile = new ExifInterface(filePath);
+        if (filePath != null) 
+            this.inFile = new ExifInterface(filePath);
+         else 
+            throw new IOException("null pointer passed to createInFile");
+        
 

 /**
@@ -63,7 +67,11 @@ public class ExifHelper 
  * @throws IOException
  */
 public void createOutFile(String filePath) throws IOException 
-        this.outFile = new ExifInterface(filePath);
+        if (filePath != null) 
+            this.outFile = new ExifInterface(filePath);
+         else 
+            throw new IOException("null pointer passed to createOutFile");
+        
 

 /**
diff --git a/src/android/FileHelper.java b/src/android/FileHelper.java
index 59f890e..cd4b6ef 100644
--- a/src/android/FileHelper.java
+++ b/src/android/FileHelper.java
@@ -33,6 +33,7 @@ import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Locale;
+import android.util.Log;

 public class FileHelper 
 private static final String LOG_TAG = "FileUtils";
@@ -54,9 +55,12 @@ public class FileHelper 
 realPath = FileHelper.getRealPathFromURI_BelowAPI11(cordova.getActivity(), uri);

 // SDK >= 11 && SDK < 19
-        else if (Build.VERSION.SDK_INT < 19)
+        else if (Build.VERSION.SDK_INT < 19) 
 realPath = FileHelper.getRealPathFromURI_API11to18(cordova.getActivity(), uri);
-
+            if (realPath == null) 
+                realPath = getRealPathFallback(uri.toString(), cordova);
+            
+        
 // SDK > 19 (Android 4.4)
 else
 realPath = FileHelper.getRealPathFromURI_API19(cordova.getActivity(), uri);
@@ -126,6 +130,47 @@ public class FileHelper 
 return result;
 

+    /**
+     * Returns the real path of the given URI string.
+     * If the given URI string represents a content:// URI, the real path is retrieved from the media store.
+     *
+     * @param uriString the URI string of the audio/image/video
+     * @param cordova the current application context
+     * @return the full path to the file
+     */
+    @SuppressWarnings("deprecation")
+    public static String getRealPathFallback(String uriString, CordovaInterface cordova) 
+        String realPath = null;
+        try 
+            if (uriString.startsWith("content://")) 
+                String[] proj =  _DATA ;
+                Cursor cursor = cordova.getActivity().managedQuery(Uri.parse(uriString), proj, null, null, null);
+                int column_index = cursor.getColumnIndexOrThrow(_DATA);
+                cursor.moveToFirst();
+                realPath = cursor.getString(column_index);
+                Log.d(LOG_TAG, "getRealPath managedQuery success uri " + uriString + " realpath " + realPath);
+                if (realPath == null) 
+                    Log.e(LOG_TAG, "getRealPath Could get real path for URI string " + uriString);
+                
+             else if (uriString.startsWith("file://")) 
+                realPath = uriString.substring(7);
+                Log.d(LOG_TAG, "getRealPath file:// " + uriString + " realpath " + realPath);
+                if (realPath.startsWith("/android_asset/")) 
+                    Log.e(LOG_TAG, "getRealPath Cannot get real path for URI string " + uriString + " because it is a file:///android_asset/ URI.");
+                    realPath = null;
+                
+             else 
+                realPath = uriString;
+            
+         catch (Exception e) 
+            Log.d(LOG_TAG, "getRealPath using uristring could not find real path, uriString: " + uriString + " message: " + e.getMessage());
+            realPath = uriString;
+        
+
+        return realPath;
+    
+
+
 public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri) 
 String[] proj =  MediaStore.Images.Media.DATA ;
 String result = null;

【讨论】:

以上是关于使用相机插件拍摄新照片时,PhoneGap 应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

相机应用程序拍摄新照片时如何生成通知?

使用 Phonegap/Cordova 相机插件从相机或图库中选择照片

如何使用 Cordova 相机插件拍摄多张照片

从图片中拍摄的照片不会显示在 android 的科尔多瓦相机插件中的裁剪

使用 Ionic 使用相机拍摄多张照片

在 iOS Phonegap 应用程序中禁用“想使用您当前的位置”警报