La aplicación se basa en webRTC vs websocket. Android studio 2.3.2 última versión.

Yo ya uso:

Protocolo https, reproducción automática, versión de Android 7.0 (mínimo> Android 5.0). La aplicación funciona en todos los navegadores compatibles, solo la vista web de Android genera errores .

Estas son las primeras líneas de errores de inicio de sesión en logcat (android studio, última versión):

E / chromium: [ERROR: audio_manager_android.cc (264)] ¡No se puede seleccionar el dispositivo de audio! E / cr_VideoCapture: allocate: manager.openCamera: SecurityException: validateConnectLocked: 1112: La persona que llama "com.testwebrtc.nikola.myapplication" no puede abrir la cámara "1" sin permiso de la cámara en android.hardware.camera2.CameraManager.throwAsPublicException (CameraManager.java: 628) en android.hardware.camera2.CameraManager.openCameraDeviceUserAsync (CameraManager.java:347) en android.hardware.camera2.CameraManager.openCamera (CameraManager.java:450) en org.chromium.media.VideoCaptureCamera2.startCapture ureCamera2.java:661)

Otra variante para el error:

[ERROR: web_contents_delegate.cc (199)] WebContentsDelegate :: CheckMediaAccessPermission: No es compatible.

Este es el registro de errores de chrome / webview (de errorCallBack - getUserMedia):

      An error occcurred [CODE NotAllowedError]

      other error variant: 

      trackstarterror

Código de Android se ve así:

package com.project.TEST.xxx;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Context;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.CookieManager;
import android.webkit.PermissionRequest;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FragmentManager fragmentManager = getFragmentManager();
        fragmentManager.beginTransaction()
                .replace(R.id.container, PlaceholderFragment.newInstance(1) )
                .commit();

    }

    /**
     * A placeholder fragment containing a simple view.
     */
    public static class PlaceholderFragment extends Fragment {
        /**
         * The fragment argument representing the section number for this
         * fragment.
         */
        private static final String ARG_SECTION_NUMBER = "section_number";

        /**
         * Returns a new instance of this fragment for the given section
         * number.
         */
        public static PlaceholderFragment newInstance(int sectionNumber) {
            PlaceholderFragment fragment = new PlaceholderFragment();
            Bundle args = new Bundle();
            args.putInt(ARG_SECTION_NUMBER, sectionNumber);
            fragment.setArguments(args);
            return fragment;
        }

        private WebView mWebRTCWebView;

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container, false);
            mWebRTCWebView = (WebView) rootView.findViewById(R.id.fragment_main_webview);

            setUpWebViewDefaults(mWebRTCWebView);

            mWebRTCWebView.loadUrl("https://example.com/");

            mWebRTCWebView.setWebChromeClient(new WebChromeClient() {

                @Override
                public void onPermissionRequest(final PermissionRequest request) {
                    Log.d(TAG, "onPermissionRequest");
                    getActivity().runOnUiThread(new Runnable() {
                        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
                        @Override
                        public void run() {

                            request.grant(request.getResources());

                        }
                    });
                }

            });

            return rootView;
        }

        @Override
        public void onStop() {
            super.onStop();

            /**
             * When the application falls into the background we want to stop the media stream
             * such that the camera is free to use by other apps.
             */
            mWebRTCWebView.evaluateJavascript("if(window.localStream){window.localStream.stop();}", null);
        }

        /*
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            ((MainActivity) activity).onSectionAttached(
                    getArguments().getInt(ARG_SECTION_NUMBER));
        }
*/

        @Override
        public void onAttach(Context context) {
            super.onAttach(context);

            Activity a;

            if (context instanceof Activity){
                a=(Activity) context;

            }

        }

        /**
         * Convenience method to set some generic defaults for a
         * given WebView
         *
         * @param webView
         */
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        private void setUpWebViewDefaults(WebView webView) {
            WebSettings settings = webView.getSettings();

            // Enable Javascript
            settings.setJavaScriptEnabled(true);

            // Use WideViewport and Zoom out if there is no viewport defined
            settings.setUseWideViewPort(true);
            settings.setLoadWithOverviewMode(true);

            // Enable pinch to zoom without the zoom buttons
            settings.setBuiltInZoomControls(true);

            // Allow use of Local Storage
            settings.setDomStorageEnabled(true);

            if(Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
                // Hide the zoom controls for HONEYCOMB+
                settings.setDisplayZoomControls(false);
            }

            // Enable remote debugging via chrome://inspect
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                WebView.setWebContentsDebuggingEnabled(true);
            }

            webView.setWebViewClient(new WebViewClient());

            // AppRTC requires third party cookies to work
            CookieManager cookieManager = CookieManager.getInstance();
            cookieManager.setAcceptThirdPartyCookies(mWebRTCWebView, true);
        }
    }


}

Build.gradle-project:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.2'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

Gradle - módulo:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.3"
    defaultConfig {
        applicationId "com.project.test.xxx"
        minSdkVersion 21
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags "-fexceptions"
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
}

Manifiesto de Android.xml:

....
  <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT" />
    <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />

    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
    <uses-feature android:name="android.hardware.camera.autofocus" android:required="true" />
    <uses-feature android:name="android.hardware.camera.front" android:required="true" />
    <uses-feature android:name="android.hardware.camera" android:required="true" />
    <uses-feature android:name="android.hardware.camera.level.full" android:required="true" />
    <uses-feature android:name="android.hardware.camera.capability.raw" android:required="true" />
    <uses-feature android:name="android.hardware.camera.any" android:required="true" />
    <uses-feature android:name="android.hardware.microphone" android:required="true" />
    <uses-feature android:name="android.hardware.camera2" android:required="true" />

...
7
Nikola Lukic 25 may. 2017 a las 15:00

3 respuestas

La mejor respuesta

Otorgue permisos de esta manera:

yourWebView.setWebChromeClient(new WebChromeClient() {
                @Override
                public void onPermissionRequest(PermissionRequest request) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        request.grant(request.getResources());
                    }
                }
            });
7
Amos 14 may. 2019 a las 09:08

El WebView solicita permiso de la aplicación, pero el usuario no le otorga estos permisos.

Debe invocar la solicitud de permiso de la aplicación al usuario, como se menciona en este documento.

Ahora descubrí que los permisos que requiere WebRTC son aquellos:

onPermissionRequest: android.webkit.resource.VIDEO_CAPTURE
onPermissionRequest: android.webkit.resource.AUDIO_CAPTURE
4
g00glen00b 5 dic. 2017 a las 15:25

Su aplicación necesita solicitar permiso antes de usar la cámara

 <uses-permission android:name="android.permission.CAMERA" />
 <uses-feature android:name="android.hardware.camera" />
 <uses-feature android:name="android.hardware.camera.autofocus" />
2
AniGame CN 25 may. 2017 a las 15:00