美文网首页1-Android开发知识
H5前端调用Android拍照功能

H5前端调用Android拍照功能

作者: Q大疯zi | 来源:发表于2018-08-01 17:34 被阅读1186次

    JS调用Android摄像头拍照


    产品经理要求H5要实现直接调用原生摄像头完成拍照功能:

    一开始也是糊涂,我们前端的哥们总说用JS可以直接调用,不用Android的Java代码,所以我一开始也信了,想了想不是那么回事,可以调用也是通过原生封装好的。

    下面写代码。先上JS的
    说明:

    1. JS含有和Android的交互,调用摄像头的方法和接收Android传递过来的照片信息
      2.对照片信息的处理(Base64的处理)(JS是自己写的,H5写的有点low见谅)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
    </head>
    <body>
    <hr>
    <hr>
    <hr>
    <button type="button" style="width: 500px;height: 200px;" id="btn1" onclick="btnOnclick()">拍照
    </button>
    <hr>
    <hr>
    
    <!--<img src="" id="img_id">-->
    <img src="http://www.runoob.com/wp-content/uploads/2013/07/pic_html5.gif" id="img_id">
    
    </body>
    <script>
    
        var receiveBase64StrData = function (json) {
            //①接收到Android传递过来的json信息
            var base64Str = json.base64EncodeImgStr;
    
            var base64 = new Base64();
            var onject = base64.decode(base64Str);
            onject = onject.replace(/[\r\n]/g, "");
            document.getElementById("img_id").src = "data:image/jpeg;base64," + onject;
    
        };
    
        btnOnclick = function () {
            window.jsInterface.takePhoto();
        };
    
    
        //1.加密解密方法使用:
    
        //1.加密
        //var str = '124中文内容';
        var base = new Base64();
        //var result = base.encode(str);
        //document.write(result);
    
        //2.解密
        var result2 = base.decode(result);
        document.write(result2);
    
        //2.加密、解密算法封装:
    
        function Base64() {
    
            // private property
            _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    
            // public method for encoding
            this.encode = function (input) {
                var output = "";
                var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
                var i = 0;
                input = _utf8_encode(input);
                while (i < input.length) {
                    chr1 = input.charCodeAt(i++);
                    chr2 = input.charCodeAt(i++);
                    chr3 = input.charCodeAt(i++);
                    enc1 = chr1 >> 2;
                    enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                    enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                    enc4 = chr3 & 63;
                    if (isNaN(chr2)) {
                        enc3 = enc4 = 64;
                    } else if (isNaN(chr3)) {
                        enc4 = 64;
                    }
                    output = output +
                        _keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
                        _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
                }
                return output;
            }
    
            // public method for decoding
            this.decode = function (input) {
                var output = "";
                var chr1, chr2, chr3;
                var enc1, enc2, enc3, enc4;
                var i = 0;
                input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
                while (i < input.length) {
                    enc1 = _keyStr.indexOf(input.charAt(i++));
                    enc2 = _keyStr.indexOf(input.charAt(i++));
                    enc3 = _keyStr.indexOf(input.charAt(i++));
                    enc4 = _keyStr.indexOf(input.charAt(i++));
                    chr1 = (enc1 << 2) | (enc2 >> 4);
                    chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                    chr3 = ((enc3 & 3) << 6) | enc4;
                    output = output + String.fromCharCode(chr1);
                    if (enc3 != 64) {
                        output = output + String.fromCharCode(chr2);
                    }
                    if (enc4 != 64) {
                        output = output + String.fromCharCode(chr3);
                    }
                }
                output = _utf8_decode(output);
                return output;
            };
    
            // private method for UTF-8 encoding
            _utf8_encode = function (string) {
                string = string.replace(/\r\n/g, "\n");
                var utftext = "";
                for (var n = 0; n < string.length; n++) {
                    var c = string.charCodeAt(n);
                    if (c < 128) {
                        utftext += String.fromCharCode(c);
                    } else if ((c > 127) && (c < 2048)) {
                        utftext += String.fromCharCode((c >> 6) | 192);
                        utftext += String.fromCharCode((c & 63) | 128);
                    } else {
                        utftext += String.fromCharCode((c >> 12) | 224);
                        utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                        utftext += String.fromCharCode((c & 63) | 128);
                    }
    
                }
                return utftext;
            }
    
            // private method for UTF-8 decoding
            _utf8_decode = function (utftext) {
                var string = "";
                var i = 0;
                var c = c1 = c2 = 0;
                while (i < utftext.length) {
                    c = utftext.charCodeAt(i);
                    if (c < 128) {
                        string += String.fromCharCode(c);
                        i++;
                    } else if ((c > 191) && (c < 224)) {
                        c2 = utftext.charCodeAt(i + 1);
                        string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                        i += 2;
                    } else {
                        c2 = utftext.charCodeAt(i + 1);
                        c3 = utftext.charCodeAt(i + 2);
                        string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                        i += 3;
                    }
                }
                return string;
            }
        }
    
    </script>
    </html>
    

    下面是Android端的代码
    说明:
    1.含有拍照逻辑
    2.对照片的处理,加密和处理旋转问题(三星拍照的照片被旋转,其他不知道)
    3.照片的bitmap太大的话需要处理压缩,以免出现OOM,这样JS端会显示不出来,这里只是简单的处理了一下,有需要的话根据需要去动态处理。

    public class MainActivity extends AppCompatActivity {
        private static final String TAG = "MainActivity";
        private WebView webView;
        private JavaScriptMethods mJsMethods;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initView();
        }
    
    
        private void initView() {
            webView = (WebView) findViewById(R.id.webview);
            initWebView();
        }
    
        private void initWebView() {
            WebSettings settings = webView.getSettings();
            settings.setJavaScriptEnabled(true);
            // 支持缩放
            initListener();
            mJsMethods = new JavaScriptMethods(MainActivity.this, this, webView);
            webView.addJavascriptInterface(mJsMethods, JavaScriptMethods.JSINTERFACE);
    
            webView.loadUrl("file:///android_asset/H5.html");
        }
    
    
        private void initListener() {
            webView.setWebChromeClient(new WebChromeClient() {
                @Override
                public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                    return super.onJsAlert(view, url, message, result);
                }
    
                @Override
                public void onProgressChanged(WebView view, final int newProgress) {
                    super.onProgressChanged(view, newProgress);
                }
    
                @Override
                public void onReceivedTitle(WebView view, String title) {
                    super.onReceivedTitle(view, title);
                }
    
            });
    
            webView.setWebViewClient(new WebViewClient() {
                @Nullable
                @Override
                public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
                    return super.shouldInterceptRequest(view, request);
                }
    
    
                @Override
                public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                    super.onReceivedError(view, errorCode, description, failingUrl);
                    //6.0以下
    
                }
    
                @RequiresApi(api = Build.VERSION_CODES.M)
                @Override
                public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
                    super.onReceivedError(view, request, error);
                }
    
    
                @Override
                public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
                    super.onReceivedHttpError(view, request, errorResponse);
                }
    
                @Override
                public void onPageStarted(WebView view, String url, Bitmap favicon) {
                    super.onPageStarted(view, url, favicon);
                }
    
                @Override
                public void onPageFinished(WebView view, String url) {
                    super.onPageFinished(view, url);
                }
    
            });
    
    
        }
    
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (resultCode == RESULT_OK && requestCode == JavaScriptMethods.TAKE_PHOTO) {
                Log.d(TAG, "拍到图片");
                //保存照片显示在H5界面
                //获取照片的旋转角度,三星的拍照后旋转了90度
                int bitmapDegree = getBitmapDegree(mJsMethods.filePath);
                Log.d("照片的旋转:", "" + bitmapDegree);
                Uri uri = Uri.fromFile(new File(mJsMethods.filePath));
                try {
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    options.inPreferredConfig = Bitmap.Config.RGB_565;
                    //参数可调,值越大图片大小越小
                    options.inSampleSize = 4;
                    Bitmap takePhotoBitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
                    //纠正旋转角度
                    Bitmap rotateBitmapByDegreebitmap = rotateBitmapByDegree(takePhotoBitmap, bitmapDegree);
                    //转64并加密,加密是因为给H5 传递json的时候会有回车换行,加密后消除,但是要在H5端做解密操作,
                    // 并除去回车换行符,在Android端做也是一样的
                    String base64ImgStr = Base64Util.bitmapToBase64(rotateBitmapByDegreebitmap);
                    String base64EncodeImgStr = Base64Util.encode(base64ImgStr);
                    JSONObject json = new JSONObject();
                    json.put("base64EncodeImgStr", base64EncodeImgStr);
                    String url = "javascript:receiveBase64StrData(" + json.toString() + ")";
                    webView.loadUrl(url);
                    takePhotoBitmap.recycle();
                    rotateBitmapByDegreebitmap.recycle();
    
                } catch (FileNotFoundException | JSONException e) {
                    e.printStackTrace();
                }
    
    
            }
        }
    
    
        /**
         * 读取图片的旋转的角度
         *
         * @param path 图片绝对路径
         * @return 图片的旋转角度
         */
        private int getBitmapDegree(String path) {
            int degree = 0;
            try {
                // 从指定路径下读取图片,并获取其EXIF信息
                ExifInterface exifInterface = new ExifInterface(path);
                // 获取图片的旋转信息
                int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                        ExifInterface.ORIENTATION_NORMAL);
                switch (orientation) {
                    case ExifInterface.ORIENTATION_ROTATE_90:
                        degree = 90;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_180:
                        degree = 180;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_270:
                        degree = 270;
                        break;
                    default:
                        break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return degree;
        }
    
        /**
         * 将图片按照某个角度进行旋转
         *
         * @param bm     需要旋转的图片
         * @param degree 旋转角度
         * @return 旋转后的图片
         */
        public Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {
            Bitmap returnBm = null;
            // 根据旋转角度,生成旋转矩阵
            Matrix matrix = new Matrix();
            matrix.postRotate(degree);
            try {
                // 将原始图片按照旋转矩阵进行旋转,并得到新的图片
                returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
            } catch (OutOfMemoryError e) {
                Log.d("内存溢出", "");
            }
            if (returnBm == null) {
                returnBm = bm;
            }
            if (bm != returnBm) {
                bm.recycle();
            }
            return returnBm;
        }
    }
    

    JS和Android的桥梁搭建
    这里就不多说了不会调用的去百度,网上很多。

    
    /**
     * JS和Android互调的桥梁
     */
    public class JavaScriptMethods {
        public static String JSINTERFACE = "jsInterface";
        private Activity mActivity;
        private WebView mWebView;
        private Context mContext;
        public  static final int TAKE_PHOTO = 1000;
        public JavaScriptMethods(Activity activity, Context context, WebView webView) {
            mActivity = activity;
            mWebView = webView;
            mContext = context;
        }
    
        public String filePath = Environment.getExternalStorageDirectory() + File.separator + "myH5camera" + File.separator + "aaa.jpg";
    
        @JavascriptInterface
        public void takePhoto() {
    //        调用系统摄像头
            Log.d("调用前置摄像头:","");
            startCamera(TAKE_PHOTO, filePath);
        }
    
    
        private void startCamera(int type, String imgName) {
            File filePath = new File(imgName);
            try {
                if (!filePath.exists()) {
                    filePath.getParentFile().mkdirs();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            Uri imageUri;
            /**
             * android7.0及以上
             */
            if (Build.VERSION.SDK_INT >= 24) {
                imageUri = FileProvider.getUriForFile(mContext, mActivity.getPackageName() + ".provider", filePath);
            } else {
                imageUri = Uri.fromFile(filePath);
            }
            //启动相机程序
            Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            mActivity.startActivityForResult(intent, type);
        }
    
    
    }
    

    最后

    给你们提供最喜欢的源码:
    点击下载

    相关文章

      网友评论

        本文标题:H5前端调用Android拍照功能

        本文链接:https://www.haomeiwen.com/subject/pvvrvftx.html