在上一篇文章Android 原生开发、H5、React-Native开发特点,我们可以了解到三种Android开发方式的区别和优缺点。[Android开发:原生+H5]系列的文章,将主要讲解Android原生+H5开发相关,这一节主要是Android原生+H5开发时要使用WebView,要使WebView正确的显示加载H5页面和功能需要做相关的配置。

AndroidManifest权限添加

  
  请一定、务必在AndroidManifest中添加如下权限,否则是无法正常打开显示H5页面的。
  这个一定要单独拿出来强调一下,以防你其他代码啊,配置啊什么的都写好了,但就是不显示,然后你就各种找问题,发愁,恼怒,耽误时间。因为楼主就曾经犯过这样的错误,真的被自己粗心蠢哭,哭哭哭……

"android.permission.INTERNET"/>

WebView使用步骤

1. 添加AndroidManifest权限。

"android.permission.INTERNET"/>

2. 布局文件

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="com.app.www.webapp.SecondActivity">    <WebView        android:id="@+id/webView"        android:layout_width="match_parent"        android:layout_height="match_parent" />LinearLayout>

3. 获取WebView对象

   webView = this.findViewById(R.id.webView);

4. WebSettings配置WebView。下面有具体的配置说明。
5. 设置加载地址。

   this.webView.loadUrl(url);

  到这一步为止,WebView就可以正常的显示了,如果我们想要对WebView做进一步的监听处理,就需要下面的设置。
  
6. 设置WebViewClient。 WebViewClient主要是监听WebView加载进程,平常我们对webview加载的处理,例如加一些进度条、跳转设置之类的都是通过WebViewClient类完成。在下面我们会讲到。
7. 设置WebChromeClient。 有时候我们不想原生去调用手机的拍照和相册,如果我们想要用H5去掉用的话,我们需要去重新WebChromeClient类,并进行设置,这样H5才能成功的调用拍照和相册。下面会细讲。

WebSettings类配置

        /**支持Js**/        setting.setJavaScriptEnabled(true);        /**设置自适应屏幕,两者合用**/        //将图片调整到适合webview的大小        setting.setUseWideViewPort(true);        // 缩放至屏幕的大小        setting.setLoadWithOverviewMode(true);        /**缩放操作**/        // 是否支持画面缩放,默认不支持        setting.setBuiltInZoomControls(true);        setting.setSupportZoom(true);        // 是否显示缩放图标,默认显示        setting.setDisplayZoomControls(false);        // 设置网页内容自适应屏幕大小        setting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);        /**设置允许JS弹窗**/        setting.setJavaScriptCanOpenWindowsAutomatically(true);        setting.setDomStorageEnabled(true);        /**关闭webview中缓存**/        setting.setCacheMode(WebSettings.LOAD_NO_CACHE);        /**设置可以访问文件 **/        setting.setAllowFileAccess(true);        setting.setAllowFileAccessFromFileURLs(true);        setting.setAllowUniversalAccessFromFileURLs(true);

WebViewClient类

  如果不进行设置WebViewClient的话,我们的WebView通常会跳转到手机自带的浏览器去进行显示,但是我们想要的是在app内显示,所以我们需要对WebViewClient进行设置。对这个类的使用我们之前在 Android 网络连接——WebView这篇文章中也讲过,这里我就只复制一下。

WebView加载失败设置

  我们在使用浏览器时,我们经常会看到,如果页面加载失败会出现一个提示的页面。我们自己的浏览器当然也少不了这个功能。设置加载页面失败调用WebView的setWebViewClient()方法,传入匿名WebViewClient对象,重写onReceivedError()方法,在该方法内进行处理。

webView.setWebViewClient(new WebViewClient() {    /*    网络连接错误时调用    */    @Override    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl){        super.onReceivedError(view, errorCode, description, failingUrl);    }});

WebView网页加载进度条显示

        webView.setWebChromeClient(new WebChromeClient() {            @Override            public void onProgressChanged(WebView view, int newProgress) {                super.onProgressChanged(view, newProgress);                progressBar.setProgress(newProgress);//网络加载时设置进度条进度            }        });        webView.setWebViewClient(new WebViewClient() {            /*            网络开始加载时调用            */            @Override            public void onPageStarted(WebView view, String url, Bitmap favicon) {                super.onPageStarted(view, url, favicon);                progressBar.setVisibility(View.VISIBLE);//设置显示进度条            }            /*            网络加载结束时调用            */            @Override            public void onPageFinished(WebView view, String url) {                super.onPageFinished(view, url);                progressBar.setVisibility(View.GONE);//设置去除进度条            }        });

WebChromeClient类

  H5想要调用我们手机的相册和拍照,直接调用是不行的,我们必须在WebView设置中进行设置。重写WebChromeClient类。

import android.annotation.SuppressLint;import android.annotation.TargetApi;import android.app.Activity;import android.content.ClipData;import android.content.ComponentName;import android.content.ContentUris;import android.content.Context;import android.content.Intent;import android.content.pm.PackageManager;import android.content.pm.ResolveInfo;import android.database.Cursor;import android.graphics.Bitmap;import android.net.Uri;import android.os.Build;import android.os.Environment;import android.os.Parcelable;import android.provider.DocumentsContract;import android.provider.MediaStore;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.KeyEvent;import android.webkit.ValueCallback;import android.webkit.WebChromeClient;import android.webkit.WebSettings;import android.webkit.WebView;import android.webkit.WebViewClient;import android.widget.Toast;import java.io.File;import java.util.ArrayList;import java.util.List;import static android.view.KeyEvent.KEYCODE_BACK;public class SecondActivity extends Activity {    private WebView webView;    private Intent intent;    private String url;    /**     * 表单的数据信息     */    private ValueCallback mUploadMessage;    private ValueCallback mUploadCallbackAboveL;    /**     * 表单的结果回调     */    private final static int FILECHOOSER_RESULTCODE = 1;    private Uri imageUri;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        intent = getIntent();        url = intent.getStringExtra("url");        Toast.makeText(this, url, Toast.LENGTH_SHORT).show();        webView = this.findViewById(R.id.webView);        initWebView();//        this.webView.loadUrl("http://192.168.1.105:8099/photo");        webView.loadUrl(url);        webView.setWebViewClient(new WebViewClient() {            @Override            public boolean shouldOverrideUrlLoading(WebView view, String url) {                return super.shouldOverrideUrlLoading(view, url);            }            @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);            }        });        webView.setWebChromeClient(new OpenFileChromeClient());    }    public class OpenFileChromeClient extends WebChromeClient {        @Override        public boolean onShowFileChooser(WebView webView,                                         ValueCallback filePathCallback,                                         FileChooserParams fileChooserParams) {            mUploadCallbackAboveL = filePathCallback;            take();            return true;        }        /**         * Android < 3.0 调用这个方法         *         * @param uploadMsg         */        public void openFileChooser(ValueCallback uploadMsg) {            mUploadMessage = uploadMsg;            take();        }        /**         * Android < 3.0 调用这个方法         *         * @param uploadMsg         * @param acceptType         */        public void openFileChooser(ValueCallback uploadMsg, String acceptType) {            mUploadMessage = uploadMsg;            take();        }        /**         * Android > 4.1.1 调用这个方法         *         * @param uploadMsg         * @param acceptType         * @param capture         */        public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) {            mUploadMessage = uploadMsg;            take();        }    }    private void initWebView() {        WebSettings setting = webView.getSettings();        /**支持Js**/        setting.setJavaScriptEnabled(true);        /**设置自适应屏幕,两者合用**/        //将图片调整到适合webview的大小        setting.setUseWideViewPort(true);        // 缩放至屏幕的大小        setting.setLoadWithOverviewMode(true);        /**缩放操作**/        // 是否支持画面缩放,默认不支持        setting.setBuiltInZoomControls(true);        setting.setSupportZoom(true);        // 是否显示缩放图标,默认显示        setting.setDisplayZoomControls(false);        // 设置网页内容自适应屏幕大小        setting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);        /**设置允许JS弹窗**/        setting.setJavaScriptCanOpenWindowsAutomatically(true);        setting.setDomStorageEnabled(true);        /**关闭webview中缓存**/        setting.setCacheMode(WebSettings.LOAD_NO_CACHE);        /**设置可以访问文件 **/        setting.setAllowFileAccess(true);        setting.setAllowFileAccessFromFileURLs(true);        setting.setAllowUniversalAccessFromFileURLs(true);    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        if (requestCode == FILECHOOSER_RESULTCODE) {            if (null == mUploadMessage && null == mUploadCallbackAboveL) return;            Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();            if (mUploadCallbackAboveL != null) {                onActivityResultAboveL(requestCode, resultCode, data);            } else if (mUploadMessage != null) {                if (result != null) {                    String path = getPath(getApplicationContext(),                            result);                    Uri uri = Uri.fromFile(new File(path));                    mUploadMessage                            .onReceiveValue(uri);                } else {                    mUploadMessage.onReceiveValue(imageUri);                }                mUploadMessage = null;            }        }    }    @Override    public boolean onKeyDown(int keyCode, KeyEvent event) {        if ((keyCode == KEYCODE_BACK) && webView.canGoBack()) {            webView.goBack();            return true;        }        return super.onKeyDown(keyCode, event);    }    @SuppressWarnings("null")    @TargetApi(Build.VERSION_CODES.BASE)    private void onActivityResultAboveL(int requestCode, int resultCode, Intent data) {        if (requestCode != FILECHOOSER_RESULTCODE                || mUploadCallbackAboveL == null) {            return;        }        Uri[] results = null;        if (resultCode == Activity.RESULT_OK) {            if (data == null) {                results = new Uri[]{imageUri};            } else {                String dataString = data.getDataString();                ClipData clipData = data.getClipData();                if (clipData != null) {                    results = new Uri[clipData.getItemCount()];                    for (int i = 0; i < clipData.getItemCount(); i++) {                        ClipData.Item item = clipData.getItemAt(i);                        results[i] = item.getUri();                    }                }                if (dataString != null)                    results = new Uri[]{Uri.parse(dataString)};            }        }        if (results != null) {            mUploadCallbackAboveL.onReceiveValue(results);            mUploadCallbackAboveL = null;        } else {            results = new Uri[]{imageUri};            mUploadCallbackAboveL.onReceiveValue(results);            mUploadCallbackAboveL = null;        }        return;    }    private void take() {        File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp");        // Create the storage directory if it does not exist        if (!imageStorageDir.exists()) {            imageStorageDir.mkdirs();        }        File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");        imageUri = Uri.fromFile(file);        final List cameraIntents = new ArrayList();        final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);        final PackageManager packageManager = getPackageManager();        final List listCam = packageManager.queryIntentActivities(captureIntent, 0);        for (ResolveInfo res : listCam) {            final String packageName = res.activityInfo.packageName;            final Intent i = new Intent(captureIntent);            i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));            i.setPackage(packageName);            i.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);            cameraIntents.add(i);        }        Intent i = new Intent(Intent.ACTION_GET_CONTENT);        i.addCategory(Intent.CATEGORY_OPENABLE);        i.setType("image/*");        Intent chooserIntent = Intent.createChooser(i, "Image Chooser");        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));        SecondActivity.this.startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);    }    @SuppressLint("NewApi")    @TargetApi(Build.VERSION_CODES.KITKAT)    public static String getPath(final Context context, final Uri uri) {        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;        // DocumentProvider        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {            // ExternalStorageProvider            if (isExternalStorageDocument(uri)) {                final String docId = DocumentsContract.getDocumentId(uri);                final String[] split = docId.split(":");                final String type = split[0];                if ("primary".equalsIgnoreCase(type)) {                    return Environment.getExternalStorageDirectory() + "/" + split[1];                }                // TODO handle non-primary volumes            }            // DownloadsProvider            else if (isDownloadsDocument(uri)) {                final String id = DocumentsContract.getDocumentId(uri);                final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));                return getDataColumn(context, contentUri, null, null);            }            // MediaProvider            else if (isMediaDocument(uri)) {                final String docId = DocumentsContract.getDocumentId(uri);                final String[] split = docId.split(":");                final String type = split[0];                Uri contentUri = null;                if ("image".equals(type)) {                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;                } else if ("video".equals(type)) {                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;                } else if ("audio".equals(type)) {                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;                }                final String selection = "_id=?";                final String[] selectionArgs = new String[]{split[1]};                return getDataColumn(context, contentUri, selection, selectionArgs);            }        }        // MediaStore (and general)        else if ("content".equalsIgnoreCase(uri.getScheme())) {            return getDataColumn(context, uri, null, null);        }        // File        else if ("file".equalsIgnoreCase(uri.getScheme())) {            return uri.getPath();        }        return null;    }    /**     * Get the value of the data column for this Uri. This is useful for     * MediaStore Uris, and other file-based ContentProviders.     *     * @param context       The context.     * @param uri           The Uri to query.     * @param selection     (Optional) Filter used in the query.     * @param selectionArgs (Optional) Selection arguments used in the query.     * @return The value of the _data column, which is typically a file path.     */    public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {        Cursor cursor = null;        final String column = "_data";        final String[] projection = {column};        try {            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);            if (cursor != null && cursor.moveToFirst()) {                final int column_index = cursor.getColumnIndexOrThrow(column);                return cursor.getString(column_index);            }        } finally {            if (cursor != null) cursor.close();        }        return null;    }    /**     * @param uri The Uri to check.     * @return Whether the Uri authority is ExternalStorageProvider.     */    public static boolean isExternalStorageDocument(Uri uri) {        return "com.android.externalstorage.documents".equals(uri.getAuthority());    }    /**     * @param uri The Uri to check.     * @return Whether the Uri authority is DownloadsProvider.     */    public static boolean isDownloadsDocument(Uri uri) {        return "com.android.providers.downloads.documents".equals(uri.getAuthority());    }    /**     * @param uri The Uri to check.     * @return Whether the Uri authority is MediaProvider.     */    public static boolean isMediaDocument(Uri uri) {        return "com.android.providers.media.documents".equals(uri.getAuthority());    }}

完整代码下载地址:下载地址

更多相关文章

  1. Android版本问题记录:Android(安卓)8.0下异常Only fullscreen opa
  2. Android横竖屏切换总结
  3. Android---网络编程之OkHttp3整体结构了解以及使用
  4. Android(安卓)layout文件中 '?' 的作用
  5. Android中如何设置RadioButton在文字的右边,图标在左边
  6. android:windowBackground 和 Android:background 的区别
  7. android padding和margin的区别
  8. Android之系统自带的文字外观设置及实际显示效果图
  9. Android中layout_gravity和gravity的区别

随机推荐

  1. 亚马逊品牌注册需要多少钱?
  2. MySQL第十二课 删除完全相同的数据
  3. 培训学前端编程有门槛吗?
  4. 快手私信xml消息名片图文卡片逆向破解如
  5. MySQL深入研究:用户管理
  6. web前端技巧分享:一场由SameSite字段引发
  7. JavaScript:作用域和闭包,构造函数类与类的
  8. 【3.29-4.4】上周精彩回顾
  9. 猜数小游戏设计
  10. Web前端架构师