简体   繁体   English

使用camera.getPicture拍照后,Cordova / phonegap崩溃

[英]Cordova/phonegap crashes after taking a picture with camera.getPicture

I'm developing an app using Cordova 2.6 and I have a problem using the camera.getPicture function on older phones (that don't have gigs of memory). 我正在使用Cordova 2.6开发应用程序,但在较旧的手机(没有大量内存)上使用camera.getPicture函数时遇到问题。

When the app opens the camera, it (the app) is moved to the background. 当应用打开相机时,它(应用)将移至背景。 Then Android's Garbage Collector kicks in and kills the app. 然后,Android的垃圾收集器启动并杀死该应用程序。 So when I've taken my picture and it is returned to my app it crashes (Force Close) with a null pointer exception. 因此,当我拍摄完照片并将其返回到我的应用程序时,它会因空指针异常而崩溃(强制关闭)。

The problem is well known but is not documented as a 'quirck'. 该问题是众所周知的,但未记录为“快速”问题。

Here's someone else with the same problem: Camera example from the docs page fails on android 2.3.x 这是其他有相同问题的人: docs页面上的相机示例在android 2.3.x上失败

The biggest problem I have is that I can't detect this. 我最大的问题是我无法检测到这一点。 If I could I might give the user a warning but now it just force closes and ruins the experience. 如果可以的话,我可以给用户一个警告,但是现在它只是强制关闭并破坏了体验。

EDIT: here's the exception from logcat: 编辑:这是logcat的例外:

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=0, result=-1, data=null} to activity

Help? 救命?

One solution is to create a custom camera plugin and save your image to a set image file. 一种解决方案是创建自定义相机插件,然后将图像保存到设置的图像文件中。 When the app reloads may it be a crash or a forced closed due to memory check for the existence of that file and continue. 重新加载应用程序时,可能是由于内存检查该文件的存在而导致崩溃或被迫关闭,然后继续。

This would require some saving a state before the camera was called so that the app could reinitialize to handle image. 这将需要在调用相机之前保存一些状态,以便该应用可以重新初始化以处理图像。

The place I believe to put a check for a previouly taken image could be in the onCreate method in your main class or onActivityResult in the camera plugin 我认为要检查以前拍摄的图像的位置可以在您的主类的onCreate方法中,或在相机插件的onActivityResult中

Here is a similar thread Taking a picture from the camera fails 20% of the time 这是一个类似的话题20%的时间从相机拍摄照片失败

Bellow is code for is what I have started on this but handling all the different camera bugs can be problematic, ie Android ACTION_IMAGE_CAPTURE Intent 贝娄是我为此而开始的代码,但是处理所有不同的相机错误可能会出现问题,即Android ACTION_IMAGE_CAPTURE Intent

To get this to work for this task you need to use the getExternalSaveFile method to save your file and then modify your oncreate / onactivityresult to handle the restarting of the app. 为了使此功能能够完成此任务,您需要使用getExternalSaveFile方法保存文件,然后修改oncreate / onactivityresult以处理应用程序的重启。

Here is Javascript to the call plugin 这是呼叫插件的Javascript

        CameraSW.takePhoto("onPhotoURISuccess");
    //Then, to get the location of the photo after you take it and load the page again
    var imgPath = CameraSW.getPhotoUri();
    console.log("capturePhotoEdit: imgPath " + imgPath);


function onPhotoURISuccess(imageURI) {

}

Register your main app so you can reach the functions in javascript 注册您的主应用程序,以便您可以使用javascript中的功能

    static public Uri getCameraSaveFile(Context context, String directory,
        String basename, boolean fixed, String ext) {
    String fileName =   your_app.getImageFileName(basename, fixed,ext);
    //"" + System.currentTimeMillis() + ".jpg";

    ContentValues values = new ContentValues();

    values.put(MediaStore.Images.Media.TITLE, fileName);

    values.put(MediaStore.Images.Media.DESCRIPTION,
            "Image capture by camera");

    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");

    Uri imageUri = context.getContentResolver().insert(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

    Log.i("MainActivity",
            "new image uri to string is " + imageUri.toString());

    Log.i("MainActivity", "new image path is " + imageUri.getPath());
    return imageUri;
}

static public Uri getExternalSaveFile(String directory, String basename,
        boolean fixed, String ext) {
    try {
        Uri newImageUri = null;
        if (ext == null)
            ext = "jpg";
        String dir_name = Environment.getExternalStorageDirectory()
                .getPath() + "/" + directory + "/";
        File path = new File(dir_name);
        Log.e(TAG, "getExternalSaveFile path = "
                +Environment.getExternalStorageDirectory().getPath() + "/"
                + directory + "/");
 // crashing here ? wtf
        if (!path.exists()) {
            try {
                Log.i(TAG, "getExternalSaveFile: mkdirs" + dir_name);
                path.mkdirs();
            } catch (Exception e) {
                Log.e(TAG,
                        "getExternalSaveFile: mkdir error" + e.getMessage());

            }
        }
        if (!path.isDirectory()) {
            Log.e(TAG, "getExternalSaveFile: file is not directory"
                    + dir_name);
            return null;
        }
        boolean setWritable = false;

        setWritable = path.setWritable(true, false);
        if (!setWritable) {
            Log.e(TAG,
                    "getExternalSaveFile Failed to set the file to writable");
        }
        File file = new File(path, your_app.getImageFileName(basename, fixed,
                ext));

        newImageUri = Uri.fromFile(file);

        Log.i(TAG, "getExternalSaveFile new image uri to string is "
                + newImageUri.toString());

        Log.i(TAG,
                "getExternalSaveFile new image path is "
                        + newImageUri.getPath());
        return newImageUri;
    } catch (Exception e) {
        Log.e(TAG, "getExternalSaveFile: main error" + e.getMessage());

    }
    return null;
}

static public String getImageFileName(String basename, boolean fixed,
        String ext) {
    String file = null;
    if (fixed) {
        file = basename + "." + ext;
    } else {
        file = basename + System.currentTimeMillis() + "." + ext;
    }
    return file;
}

public void takePhoto(final String callback) {
    Log.v(TAG, "takePhoto: Starting takePhoto: " + callback);

    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    Log.v(TAG, "takePhoto: new intent");
    //Uri path = getExternalSaveFile("your_app", "question_", true, "jpg");
    Uri path = getCameraSaveFile(this,"your_app", "question_", true, "jpg");
    if (path == null) {
        Log.e(TAG, "takePhoto: path is not writable or can not be found");
        // should pass error on ward to phonegap
        return;
    }
    image_uri  = path.toString();
    intent.putExtra(MediaStore.EXTRA_OUTPUT, path);
    Log.v(TAG, "takePhoto: getExternalSaveFile");

    intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);

    // Intent intent = new
    // Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    // intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT,
    // Uri.fromFile(new File(folderPath, filePath)));
    if (your_app.webView != null && your_app.webView.pluginManager != null) {

        CameraSWPlugin plugin = (CameraSWPlugin)your_app.webView.pluginManager.getPlugin("CameraSW");
        if (plugin == null) {
            Log.e(TAG, "takePhoto: startActivityForResult: plugin CameraSWPlugin null make sure plugin is listed in config.xml <plugin name=\"CameraSW\" value=\"com.your_app.your_app.CameraSWPlugin\" />");
            throw new NullPointerException("takePhoto: startActivityForResult: plugin CameraSWPlugin null make sure plugin is listed in config.xml <plugin name=\"CameraSW\" value=\"com.your_app.your_app.CameraSWPlugin\" />");
        } else {
            plugin.setPath(path);
            plugin.setSuccess_callback(callback);
        startActivityForResult(
                plugin,
                intent, TAKE_PICTURE);
        Log.v(TAG, "takePhoto: startActivityForResult");
        }
    } else {
        // should not happen
        Log.v(TAG, "webView or Pluginmanager not read");
    }
}

public String getPhotoUri() {
    return image_uri;
//      return Uri.fromFile(new File(folderPath, filePath)).toString();
}

The plugin file CameraSWPlugin.java 插件文件CameraSWPlugin.java

package com.your_app.your_app;

import static com.your_app.your_app.CommonUtilities.TAKE_PICTURE;

import java.io.File;

import org.apache.cordova.api.CallbackContext;
import org.apache.cordova.api.CordovaPlugin;
import org.apache.cordova.api.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import static com.your_app.your_app.CommonUtilities.TAG;
/**
 *   I did not include the    
 * This class echoes a string called from JavaScript.
 */
public class CameraSWPlugin extends CordovaPlugin {
    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        if (action.equals("echo")) {
            String message = args.getString(0); 
            your_app.invalidate();
            this.echo(message, callbackContext);
            return true;
        }
        return false;
    }

    private void echo(String message, CallbackContext callbackContext) {
        if (message != null && message.length() > 0) { 
            callbackContext.success(message);
        } else {
            callbackContext.error("Expected one non-empty string argument.");
        }
    }



@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    Log.v(TAG, "Photo onActivityResult requestCode = " + requestCode + " resultCode = " + resultCode + " data = " + data);
    switch (requestCode) {
        case TAKE_PICTURE:
            if (resultCode == Activity.RESULT_OK) {
                //Do whatever you need to do when the camera returns
                //This is after the picture is already saved, we return to the page
                if (this.path != null) {
                    // 

                    try {
                        this.sendJavascript(path.toString());
                    } catch (Exception e) {
                        Log.v(TAG, "onActivityResult: path json error " + e.getMessage());                  
                        e.printStackTrace();
                    }
                } else {
                    Log.v(TAG, "onActivityResult: path was not set " + requestCode);                    
                }
            }
            break;
        default:
            Log.v(TAG, "Something strange happened... " + requestCode);
            break;
    }
}
private String success_callback = null;
private Uri path = null;
public String getSuccess_callback() {
    return success_callback;
}

public void setSuccess_callback(String success_callback) {
    this.success_callback = success_callback;
}

public  void sendJavascript( JSONObject _json )
{

String _d =  "javascript:"+this.success_callback+"(" + _json.toString() + ")";
      Log.v(TAG + ":sendJavascript", _d);

      if (this.success_callback != null ) {
          this.webView.sendJavascript( _d );
      }
}


public  void sendJavascript( String _json )
{

String _d =  "javascript:"+this.success_callback+"(" + JSONObject.quote(_json) + ")";
      Log.v(TAG + ":sendJavascript", _d);

      if (this.success_callback != null ) {
          this.webView.sendJavascript( _d );
      }
}

public void setPath(Uri path) {
    this.path = path;   
}

}

And be sure to add to your config.xml 并确保添加到您的config.xml中

 <plugin name="CameraSW" value="com.your_app.your_app.CameraSWPlugin" />

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM