Selaa lähdekoodia

Add ability to choose from camera or gallery when uploading files

some codes from andreipfeiffer/react-native-webview-android-file-upload
islxyqwe 6 vuotta sitten
vanhempi
commit
1269346c73

+ 3 - 0
android/build.gradle

@@ -33,3 +33,6 @@ android {
         disable 'InvalidPackage'
     }
 }
+dependencies {
+    compile "com.android.support:support-v4:22.1.0"
+}

+ 13 - 0
android/src/main/AndroidManifest.xml

@@ -1,3 +1,16 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
           package="com.flutter_webview_plugin">
+    <application>
+        <provider
+            android:name="android.support.v4.content.FileProvider"
+            android:authorities="${applicationId}.fileprovider"
+            android:exported="false"
+            android:grantUriPermissions="true" 
+            tools:replace="android:authorities">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/filepaths" />
+        </provider>
+    </application>
 </manifest>

+ 5 - 3
android/src/main/java/com/flutter_webview_plugin/FlutterWebviewPlugin.java

@@ -24,18 +24,20 @@ import io.flutter.plugin.common.PluginRegistry;
 public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.ActivityResultListener {
     private Activity activity;
     private WebviewManager webViewManager;
+    private Context context;
     static MethodChannel channel;
     private static final String CHANNEL_NAME = "flutter_webview_plugin";
 
     public static void registerWith(PluginRegistry.Registrar registrar) {
         channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME);
-        final FlutterWebviewPlugin instance = new FlutterWebviewPlugin(registrar.activity());
+        final FlutterWebviewPlugin instance = new FlutterWebviewPlugin(registrar.activity(),registrar.activeContext());
         registrar.addActivityResultListener(instance);
         channel.setMethodCallHandler(instance);
     }
 
-    private FlutterWebviewPlugin(Activity activity) {
+    private FlutterWebviewPlugin(Activity activity, Context context) {
         this.activity = activity;
+        this.context = context;
     }
 
     @Override
@@ -100,7 +102,7 @@ public class FlutterWebviewPlugin implements MethodCallHandler, PluginRegistry.A
         boolean geolocationEnabled = call.argument("geolocationEnabled");
 
         if (webViewManager == null || webViewManager.closed == true) {
-            webViewManager = new WebviewManager(activity);
+            webViewManager = new WebviewManager(activity, context);
         }
 
         FrameLayout.LayoutParams params = buildLayoutParams(call);

+ 105 - 6
android/src/main/java/com/flutter_webview_plugin/WebviewManager.java

@@ -5,6 +5,7 @@ import android.net.Uri;
 import android.util.Log;
 import android.annotation.TargetApi;
 import android.app.Activity;
+import android.content.Context;
 import android.os.Build;
 import android.view.KeyEvent;
 import android.view.View;
@@ -17,9 +18,17 @@ import android.webkit.WebSettings;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 import android.widget.FrameLayout;
+import android.provider.MediaStore;
+import android.support.v4.content.FileProvider;
 
+import java.util.List;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
+import java.io.File;
+import java.util.Date;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
 
 import io.flutter.plugin.common.MethodCall;
 import io.flutter.plugin.common.MethodChannel;
@@ -35,6 +44,7 @@ class WebviewManager {
     private ValueCallback<Uri> mUploadMessage;
     private ValueCallback<Uri[]> mUploadMessageArray;
     private final static int FILECHOOSER_RESULTCODE=1;
+    private Uri fileUri;
 
     @TargetApi(7)
     class ResultHandler {
@@ -47,6 +57,8 @@ class WebviewManager {
                         String dataString = intent.getDataString();
                         if(dataString != null){
                             results = new Uri[]{ Uri.parse(dataString) };
+                        }else if(fileUri != null){
+                            results = new Uri[]{ fileUri };
                         }
                     }
                     if(mUploadMessageArray != null){
@@ -76,10 +88,12 @@ class WebviewManager {
     WebView webView;
     Activity activity;
     ResultHandler resultHandler;
+    Context context;
 
-    WebviewManager(final Activity activity) {
+    WebviewManager(final Activity activity, final Context context) {
         this.webView = new ObservableWebView(activity);
         this.activity = activity;
+        this.context = context;
         this.resultHandler = new ResultHandler();
         WebViewClient webViewClient = new BrowserClient();
         webView.setOnKeyListener(new View.OnKeyListener() {
@@ -158,11 +172,29 @@ class WebviewManager {
                 }
                 mUploadMessageArray = filePathCallback;
 
-                Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
-                contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
-                contentSelectionIntent.setType("*/*");
-                Intent[] intentArray;
-                intentArray = new Intent[0];
+                final String[] acceptTypes = getSafeAcceptedTypes(fileChooserParams);
+                List<Intent> intentList = new ArrayList<Intent>();
+                if (acceptsImages(acceptTypes)) {
+                    Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+                    fileUri = getOutputFilename(MediaStore.ACTION_IMAGE_CAPTURE);
+                    takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
+                    intentList.add(takePhotoIntent);
+                }
+                if (acceptsVideo(acceptTypes)) {
+                    Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
+                    fileUri = getOutputFilename(MediaStore.ACTION_VIDEO_CAPTURE);
+                    takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
+                    intentList.add(takeVideoIntent);
+                }
+                Intent contentSelectionIntent;
+                if (Build.VERSION.SDK_INT >= 21) {
+                    contentSelectionIntent = fileChooserParams.createIntent();
+                } else {
+                    contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
+                    contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
+                    contentSelectionIntent.setType("*/*");
+                }
+                Intent[] intentArray = intentList.toArray(new Intent[intentList.size()]);
 
                 Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
                 chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
@@ -174,6 +206,73 @@ class WebviewManager {
         });
     }
 
+    private Uri getOutputFilename(String intentType) {
+        String prefix = "";
+        String suffix = "";
+
+        if (intentType == MediaStore.ACTION_IMAGE_CAPTURE) {
+            prefix = "image-";
+            suffix = ".jpg";
+        } else if (intentType == MediaStore.ACTION_VIDEO_CAPTURE) {
+            prefix = "video-";
+            suffix = ".mp4";
+        }
+
+        String packageName = context.getPackageName();
+        File capturedFile = null;
+        try {
+            capturedFile = createCapturedFile(prefix, suffix);
+        } catch (IOException e) {
+            Log.e("CREATE FILE", "Error occurred while creating the File", e);
+            e.printStackTrace();
+        }
+        return FileProvider.getUriForFile(context, packageName + ".fileprovider", capturedFile);
+    }
+
+    private File createCapturedFile(String prefix, String suffix) throws IOException {
+        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+        String imageFileName = prefix + "_" + timeStamp;
+        File storageDir = context.getExternalFilesDir(null);
+        return File.createTempFile(imageFileName, suffix, storageDir);
+    }
+
+    private Boolean acceptsImages(String[] types) {
+        return isArrayEmpty(types) || arrayContainsString(types, "image");
+    }
+
+    private Boolean acceptsVideo(String[] types) {
+        return isArrayEmpty(types) || arrayContainsString(types, "video");
+    }
+
+    private Boolean arrayContainsString(String[] array, String pattern) {
+        for (String content : array) {
+            if (content.contains(pattern)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private Boolean isArrayEmpty(String[] arr) {
+        // when our array returned from getAcceptTypes() has no values set from the
+        // webview
+        // i.e. <input type="file" />, without any "accept" attr
+        // will be an array with one empty string element, afaik
+        return arr.length == 0 || (arr.length == 1 && arr[0].length() == 0);
+    }
+
+    private String[] getSafeAcceptedTypes(WebChromeClient.FileChooserParams params) {
+
+        // the getAcceptTypes() is available only in api 21+
+        // for lower level, we ignore it
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            return params.getAcceptTypes();
+        }
+
+        final String[] EMPTY = {};
+        return EMPTY;
+    }
+
     private void clearCookies() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
             CookieManager.getInstance().removeAllCookies(new ValueCallback<Boolean>() {

+ 20 - 0
android/src/main/res/xml/filepaths.xml

@@ -0,0 +1,20 @@
+<paths>
+    <external-path
+            name="external-path"
+            path="."/>
+    <external-cache-path
+            name="external-cache-path"
+            path="."/>
+    <external-files-path
+            name="external-files-path"
+            path="."/>
+    <files-path
+            name="files_path"
+            path="."/>
+    <cache-path
+            name="cache-path"
+            path="."/>
+    <root-path
+            name="name"
+            path="."/>
+</paths>