Search code examples
c#androidxamarinwebviewcamera

Xamarin android webview dont open camera


I am really beginner in xamarin. I need an app, what is load a website in webview. The site need file uploading <input type="file" accept="image/*" />. In mobile browser it is perfect, can open camera or choose from storage. IOS webview working too, I gave permission and it is OK. But in android, I tried a lot of code, but the best result a filechooser without camera, and it doesn’t even load the image I select from storage. Can anyone help, what is the problem? My current code:

public class MainActivity : AppCompatActivity
    {
    private static IValueCallback mUploadMessage;
    private static int FILECHOOSER_RESULTCODE = 1;
    public static  IValueCallback mUMA; 
    public static int FCR = 1;  

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        SetContentView(Resource.Layout.activity_main);

        var web = this.FindViewById<WebView>(Resource.Id.wv);
        web.Settings.JavaScriptEnabled = true;
        web.SetWebChromeClient(new myWebChromeClient(this));
        web.LoadUrl....
    }
    protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)
    {
        if (requestCode == FILECHOOSER_RESULTCODE)
        {
            if (null == mUploadMessage) return;
            Android.Net.Uri result = intent == null || resultCode != Result.Ok ? null : intent.Data;
            mUploadMessage.OnReceiveValue(result);
            mUploadMessage = null;
        }
    }
    public class myWebChromeClient : WebChromeClient
    {
        Activity mActivity = null;
        public myWebChromeClient(Activity activity)
        {
            mActivity = activity;
        }
        public override bool OnShowFileChooser(WebView webView, IValueCallback filePathCallback, FileChooserParams fileChooserParams)
        {
            if (MainActivity.mUMA != null)
            {
                mUMA.OnReceiveValue(null);
            }
            mUMA = filePathCallback;
            Intent captureIntent = fileChooserParams.CreateIntent();
            Intent contentSelectionIntent = new Intent(Intent.ActionGetContent);
            contentSelectionIntent.AddCategory(Intent.CategoryOpenable);
            contentSelectionIntent.SetType("*/*");
            Intent[] intentArray;
            if (captureIntent != null)
            {
                intentArray = new Intent[] { captureIntent };
            }
            else
            {
                intentArray = new Intent[0];
            }

            Intent chooserIntent = new Intent(Intent.ActionChooser);
            chooserIntent.PutExtra(Intent.ExtraIntent, contentSelectionIntent);
            chooserIntent.PutExtra(Intent.ExtraTitle, "Image Chooser");
            chooserIntent.PutExtra(Intent.ExtraInitialIntents, intentArray);
            mActivity.StartActivityForResult(chooserIntent, FCR);
            return base.OnShowFileChooser(webView, filePathCallback, fileChooserParams);
        }
    }
}

Solution

  • I write a demo to open the camera by Input button in HTML page, I used local HTML page to make a test, here is running GIF.

    enter image description here

    Here is my code in MainActivity.cs.

    using Android.App;
    using Android.OS;
    using Android.Support.V7.App;
    using Android.Runtime;
    using Android.Widget;
    using Android.Webkit;
    using Android.Content;
    using Java.IO;
    using Android.Net;
    using Android.Support.V4.Content;
    using Android;
    using Android.Content.PM;
    
    namespace MyWebviewDemo
    {
        [Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true,LaunchMode =Android.Content.PM.LaunchMode.SingleTop)]
        public class MainActivity : AppCompatActivity
        {
            private static IValueCallback mUploadMessage;
            private static int FILECHOOSER_RESULTCODE = 1;
            public static IValueCallback mUMA;
            public static int FCR = 1;
            public static IValueCallback mUploadCallbackAboveL;
            public static int PHOTO_REQUEST=10023;
            public static Uri imageUri;
           public static MainActivity Instance;
            protected override void OnCreate(Bundle savedInstanceState)
            {
                base.OnCreate(savedInstanceState);
                Xamarin.Essentials.Platform.Init(this, savedInstanceState);
                // Set our view from the "main" layout resource
                SetContentView(Resource.Layout.activity_main);
                WebView webView1 = FindViewById<WebView>(Resource.Id.webView1);
                webView1.Settings.JavaScriptEnabled = true;
                webView1.Settings.UseWideViewPort=true;
                webView1.Settings.LoadWithOverviewMode=true;
                webView1.Settings.DomStorageEnabled=true;
                webView1.Settings.DefaultTextEncodingName="UTF-8";
                webView1.SetWebViewClient(new MyWebViewClient(this));
                webView1.SetWebChromeClient(new myWebChromeClient(this));
                webView1.LoadUrl("file:///android_asset/index.html");
                Instance = this;
     if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.Camera) != (int)Permission.Granted)
                {
                    RequestPermissions(new string[] { Manifest.Permission.Camera }, 0);
                }
    
    
                //开启存储权限
                if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) != (int)Permission.Granted)
                {
                    RequestPermissions(new string[] { Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage }, 0);
                }
    
    
    
    
            }
            protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)
            {
                if (requestCode == FILECHOOSER_RESULTCODE)
                {
                    if (null == mUploadMessage) return;
                    Android.Net.Uri result = intent == null || resultCode != Result.Ok ? null : intent.Data;
                    mUploadMessage.OnReceiveValue(result);
                    mUploadMessage = null;
                }else if (requestCode== PHOTO_REQUEST)
                {
                    Uri result = intent == null || resultCode != Result.Ok ? null : intent.Data;
    
                    if (mUploadCallbackAboveL != null)
                    {
                        onActivityResultAboveL(requestCode, resultCode, intent);
                    }
                    else if (mUploadMessage != null)
                    {
                        mUploadMessage.OnReceiveValue(result);
                        mUploadMessage = null;
                    }
    
                    //mUploadMessage.OnReceiveValue(result);
                    //mUploadMessage = null;
                }
            }
            private void onActivityResultAboveL(int requestCode, Result resultCode, Intent data)
            {
                if (requestCode != PHOTO_REQUEST || mUploadCallbackAboveL == null)
                {
                    return;
                }
                Uri[] results = null;
                if (resultCode == Result.Ok)
                {
                    results = new Uri[] { imageUri };
                    results[0] = MainActivity.imageUri;
                    //if (data == null)
                    //{
                    //    results = new Uri[] { imageUri };
                    //}
                    //else
                    //{
                    //    results[0] = MainActivity.imageUri;
                    //    //get the data
                    //    string dataString = data.DataString;
                    //    ClipData clipData = data.ClipData;
                    //    if (clipData != null)
                    //    {
                    //        results = new Uri[clipData.ItemCount];
                    //        for (int i = 0; i < clipData.ItemCount; i++)
                    //        {
                    //            ClipData.Item item = clipData.GetItemAt(i);
                    //            results[i] = item.Uri;
                    //        }
                    //    }
    
                    //    if (dataString != null)
                    //        results = new Uri[] { Uri.Parse(dataString) };
                    //}
                }
                mUploadCallbackAboveL.OnReceiveValue(results);
                mUploadCallbackAboveL = null;
            }
    
            public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
            {
                Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
    
                base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
            }
        }
    
        internal class MyWebViewClient : WebViewClient
        {
            private MainActivity mainActivity;
    
            public MyWebViewClient(MainActivity mainActivity)
            {
                this.mainActivity = mainActivity;
            }
        }
    
        public class myWebChromeClient : WebChromeClient
        {
            Activity mActivity = null;
            public myWebChromeClient(Activity activity)
            {
                mActivity = activity;
            }
            public override bool OnShowFileChooser(WebView webView, IValueCallback filePathCallback, FileChooserParams fileChooserParams)
            {
                MainActivity.mUploadCallbackAboveL = filePathCallback;
                TakePhoto();
                //if (MainActivity.mUMA != null)
                //{
                //    MainActivity.mUMA.OnReceiveValue(null);
                //}
                //MainActivity.mUMA = filePathCallback;
                //Intent captureIntent = fileChooserParams.CreateIntent();
                //Intent contentSelectionIntent = new Intent(Intent.ActionGetContent);
                //contentSelectionIntent.AddCategory(Intent.CategoryOpenable);
                //contentSelectionIntent.SetType("*/*");
                //Intent[] intentArray;
                //if (captureIntent != null)
                //{
                //    intentArray = new Intent[] { captureIntent };
                //}
                //else
                //{
                //    intentArray = new Intent[0];
                //}
    
                //Intent chooserIntent = new Intent(Intent.ActionChooser);
                //chooserIntent.PutExtra(Intent.ExtraIntent, contentSelectionIntent);
                //chooserIntent.PutExtra(Intent.ExtraTitle, "Image Chooser");
                //chooserIntent.PutExtra(Intent.ExtraInitialIntents, intentArray);
                //mActivity.StartActivityForResult(chooserIntent, MainActivity.FCR);
                return true;
            }
    
            private void TakePhoto()
            {
                File fileUri = new File(Environment.ExternalStorageDirectory.Path);
                //MainActivity.imageUri = Uri.FromFile(fileUri);
                if (Build.VERSION.SdkInt >=Android.OS.BuildVersionCodes.N)
                {
                    if (!fileUri.Exists())
                    {
                        fileUri.Mkdir();
                    }
                    File file = new File(fileUri, SystemClock.CurrentThreadTimeMillis()+".jpg");
                    MainActivity.imageUri = FileProvider.GetUriForFile(mActivity, "com.companyname.mywebviewdemo" + ".fileprovider", file);//通过FileProvider创建一个content类型的Uri
                }
                PhotoUtils.TakePicture(MainActivity.Instance, MainActivity.imageUri, MainActivity.PHOTO_REQUEST);
            }
    
        }
    }
    

    Here is my Util.cs to take a camera.

     public static void TakePicture(Activity activity, Android.Net.Uri imageUri, int requestCode)
            {
               
                Intent intentCamera = new Intent();
              
                intentCamera.SetAction(MediaStore.ActionImageCapture);
                
    
               // intentCamera.PutExtra(MediaStore.ExtraOutput, imageUri);
                if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.N)
                {
    
                    intentCamera.AddFlags(ActivityFlags.GrantReadUriPermission); 
                }
                if (activity != null)
                {
                    activity.StartActivityForResult(intentCamera, requestCode);
                }
            }
    

    I update my demo to github, you can downdload it and test it.

    https://github.com/851265601/Xamarin.Android_ListviewSelect/blob/master/MyWebviewDemo.zip