Search code examples
asp.net-mvc-4android-studiogetusermedia

Getusermedia does not work in webview for api 19 device


I have a MVC 4 web app that uses get user media. I also have an android webview that targets api 18, The device is api 19, but the error I get from the console log is

 source: https://dev.*****.com/truck/home/addpic?truck=C090P (0)
 11-25 11:40:19.705 32382-32382/*****.com.trucksurvey I/chromium: [INFO:CONSOLE(0)] "The page at https://dev.****.com/truck/home/addpic?truck=C090P displayed insecure content from android-webview:default_video_poster/8264335106592469907.

The app works fine on a laptop in chrome, on a phone I cannot get it to work though.

There is a SSL cert attached, and it uses getusermedia() to use the camera and take a picture Here is the code:

JS from MVC app:

/*
** My jquery/js for handleing the image taking portion 
**
*/
if (window.location.href.indexOf("addpic") > -1) {
var canvas = document.getElementById("kfCanvas"),
       context = canvas.getContext("2d"),
       video = document.getElementById("video");
var canvas2 = document.getElementById("Canvas"),
       context2 = canvas2.getContext("2d"),
       video = document.getElementById("video");
// Put event listeners into place
window.addEventListener("DOMContentLoaded", function () {
    // Grab elements, create settings, etc.
    var videoObj = { "video": true, video: {width:400, height:300},"facingMode": "environment" },
        errBack = function (error) {
            console.log("Video capture error: ", error.code);
            $("#drawingForm").hide();
        };

    // Put video listeners into place
    if (navigator.getUserMedia) { // Standard
        navigator.getUserMedia(videoObj, function (stream) {
            video.src = stream;
            video.play();
        }, errBack);
    } else if (navigator.webkitGetUserMedia) { // WebKit-prefixed
        navigator.webkitGetUserMedia(videoObj, function (stream) {
            video.src = window.webkitURL.createObjectURL(stream);
            video.play();
        }, errBack);
    }
    else if (navigator.mozGetUserMedia) { // Firefox-prefixed
        navigator.mozGetUserMedia(videoObj, function (stream) {
            video.src = window.URL.createObjectURL(stream);
            video.play();
        }, errBack);
    }
}, false);
document.getElementById("snap").addEventListener("click", function () {
    context.drawImage(video, 0, 0, 800, 600);
    context2.drawImage(video, 0, 0, 400, 300);
    // Generate the image data
    var Pic = canvas.toDataURL("image/png");
    Pic = Pic.replace(/^data:image\/(png|jpg);base64,/, "")
    $("#vid").hide();
    $("#drawingForm").show();
    $('kfCanvas').hide();
});

$("#btnSave").click(function () {
    var form = $("#drawingForm");
    var image = document.getElementById("kfCanvas").toDataURL("image/png");
    image = image.replace('data:image/png;base64,', '');
    $("#imageData").val(image);
    form.submit();
});
$("#btnRedo").click(function () {
    $("#vid").show();
    $("#drawingForm").hide();
});

}

my view from MVC 4:

@model truckEval.Models.DrawingModel


@{
ViewBag.Title = "Add a picture";
}
<div style="margin-left:0px;">
<div style="position:absolute;z-index:1000;max-width:480px;" id="vid">
<button id="snap" >Snap Photo</button>
<video id="video" width="400" height="300" autoplay></video>

</div>
 <div style="position:absolute;">
@using (Html.BeginForm(null, null, FormMethod.Post, new { id ="drawingForm" }))
{


       <input type="hidden" name="imageData" id="imageData" />
       <input type="button"  id="btnSave" value="Save Image" />
       <input type="button"  id="btnRedo" value="Try Again" />
       <input type="hidden" name="trucknum"  value="@ViewBag.trucknum" />
        <input type="hidden" name="tID" value="@ViewBag.ID" />

 <canvas id="Canvas" width="400" height="300">Sorry, your browser doesn't support canvas technology.
       </canvas>


}
</div>
<div style="display:none">
 <canvas id="kfCanvas"  width="800" height="600">Sorry, your browser doesn't support canvas technology.
       </canvas>
</div>

</div>
 <div style="margin-left:500px;">

 <h2>Truck# @ViewBag.ID</h2>

<div style="position:relative;"> 
  <a class="ui-btn ui-btn-up-b ui-shadow ui-btn-corner-all" style="padding-top:10px;padding-bottom:10px;width:25%;" href="@Url.Action("Index","home")" >Back home</a> 

</div>
<br />
</div>

The online help suggest I set my web settings to the following

      webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);

but that is only api 21 which does not fix my issue, actually the app just crashes. How do I fix this for both the webview and chrome on a phone.

my android webview code:

 import android.annotation.TargetApi;
 import android.content.Intent;
 import android.net.Uri;
 import android.net.http.SslError;
 import android.os.Build;
 import android.support.v7.app.AppCompatActivity;
 import android.os.Bundle;
 import android.util.Log;
 import android.webkit.PermissionRequest;
 import android.webkit.SslErrorHandler;
 import android.webkit.WebChromeClient;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;

public class MainActivity extends AppCompatActivity {
private String TAG ="MainActivity";
public WebView webview;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //webview use to call own site
    webview =(WebView)findViewById(R.id.webView);
    // for regular sites
   // webview.setWebViewClient(new WebViewClient());
    // for ssl certs that look invalid
    webview.setWebViewClient(new SSLTolerentWebViewClient());
    webview.getSettings().setJavaScriptEnabled(true);
    if (Build.VERSION.SDK_INT >= 21) {
        webview.getSettings().setMixedContentMode( WebSettings.MIXED_CONTENT_ALWAYS_ALLOW );
    }

    // for camera only
    webview.getSettings().setAllowContentAccess(true);
   // webview.getSettings().setJavaScriptEnabled(true);
    webview.getSettings().setAllowFileAccessFromFileURLs(true);
    webview.getSettings().setAllowUniversalAccessFromFileURLs(true);
    webview.getSettings().setMediaPlaybackRequiresUserGesture(false);
    webview.setWebChromeClient( new WebChromeClient(){
        @Override
        public void onPermissionRequest(final PermissionRequest request){
            Log.d(TAG, "onPermissionRequest");
            MainActivity.this.runOnUiThread(new Runnable(){

                @TargetApi(Build.VERSION_CODES.LOLLIPOP)
                @Override
                public void run(){
                    request.grant(request.getResources( ));
                }
            });
        }

    });


    webview.getSettings().setAllowContentAccess(true);

    webview.getSettings().setDomStorageEnabled(true);
    if (Build.VERSION.SDK_INT <= 18) {
        webview.getSettings().setSavePassword(false);

    } else {
        // do nothing. because as google mentioned in the documentation -
        // "Saving passwords in WebView will not be supported in future versions"
    }
    webview.getSettings().setSaveFormData(false);
    webview.clearFormData();

    String url = "https://dev.*****.com/truck";

    webview.loadUrl(url);
}
// for ssl certs that appear invalid
private class SSLTolerentWebViewClient extends WebViewClient {
    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        handler.proceed(); // Ignore SSL certificate errors
    }
}
}

Solution

  • It is because API 18 or lower operates in "quirks mode" as defined in official documentation.

    Note: If your targetSdkVersion is set to "18" or lower, WebView operates in "quirks mode" in order to avoid some of the behavior changes described below, as closely as possible—while still providing your app the performance and web standards upgrades. Beware, though, that single and narrow column layouts and default zoom levels are not supported at all on Android 4.4, and there may be other behavioral differences that have not been identified, so be sure to test your app on Android 4.4 or higher even if you keep your targetSdkVersion set to "18" or lower.

    More on: https://developer.android.com/guide/webapps/migrating.html