WebView详细使用三(WebView初始化和Activity的封装)

一、WebView初始化(接口定义)

WebView初始化主要分为三步:

  1. 设置WebSettings,打开WebView一些默认关闭的设置。
  2. 设置WebViewClient,对一些特殊链接统一处理。
  3. 设置WebChromeClient,对Html标题、页面加载进度、相机相册打开回调等进行一个监听。
    对于以上三点,定义出一个接口来初始化设置:
/**
 * WebView初始化接口定义
 */

public interface IWebViewInit {
    /**
     * 1. 初始化和设置WebView
     */
    WebView initWebView(WebView webView);

    /**
     * 2. 初始化WebViewClient
     */
    WebViewClient initWebViewClient();

    /**
     * 3. 初始化WebChromeClient
     */
    WebChromeClient initWebChromeClient();
}
二、IWebViewInit接口实现类WebViewInitImpl
/**
 * WebView初始化的定义
 */

public class WebViewInitImpl implements IWebViewInit {

    private static final String USER_AGENT = "appXXX";


    private WebChromeClientImpl mWebChromeClient;
    private Activity mActivity;

    public WebViewInitImpl(Activity activity) {
        mActivity = activity;
    }

    @Override
    public WebView initWebView(WebView webView) {
        webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
        WebSettings webSetting = webView.getSettings();
        webSetting.setUserAgentString(USER_AGENT + webSetting.getUserAgentString());

        webSetting.setDatabaseEnabled(true);
        webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH);
        webSetting.setTextSize(WebSettings.TextSize.NORMAL);

        // ===设置JS可用
        webSetting.setJavaScriptEnabled(true);
        // JS打开窗口
        webSetting.setJavaScriptCanOpenWindowsAutomatically(true);
        // ===设置JS可用
        // 可以访问文件
        webSetting.setAllowFileAccess(true);
        // ===缩放可用
        webSetting.setSupportZoom(true);
        webSetting.setDisplayZoomControls(false); //隐藏原生的缩放控件
        webSetting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS); //设置缩放功能   //能不能缩放 取决于网页设置
        webSetting.setLoadWithOverviewMode(true);
        webSetting.setBuiltInZoomControls(true);
        // ===缩放可用
        // 支持多窗口
        webSetting.setSupportMultipleWindows(true);
        // ===============缓存
        webSetting.setCacheMode(WebSettings.LOAD_DEFAULT);// 决定是否从网络上取数据。
        webSetting.setAppCacheEnabled(true);
        // ===============缓存
        webSetting.setUseWideViewPort(true);
        webSetting.setAppCacheMaxSize(Long.MAX_VALUE);
        webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND);
        // ==定位
        webSetting.setDomStorageEnabled(true);
        webSetting.setGeolocationEnabled(true);
        // ==定位
        return webView;
    }

    @Override
    public WebViewClient initWebViewClient() {
        return new WebViewClientImpl();
    }

    @Override
    public WebChromeClient initWebChromeClient() {
        mWebChromeClient = new WebChromeClientImpl(mActivity);
        return mWebChromeClient;
    }

    /**
     * 页面标题、进度回调
     */
    public void setOnWebChromeListener(WebChromeClientImpl.OnWebChromeListener onWebChromeListener) {
        if (mWebChromeClient != null) {
            mWebChromeClient.setOnWebChromeListener(onWebChromeListener);
        }

    }

    /**
     * 选择相机相册处理
     */
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (mWebChromeClient != null) {
            mWebChromeClient.onActivityResult(requestCode, resultCode, data);
        }
    }
}
三、WebViewClient 实现类WebViewClientImpl
/**
 * 对加载Url回调统一处理
 * 根据公司业务,自行处理
 */

public class WebViewClientImpl extends WebViewClient {

    @Override
    public boolean shouldOverrideUrlLoading(WebView webView, String url) {
        if (webView != null && url != null) {
            Context context = webView.getContext();
            if (url.endsWith(".apk")) {
                Uri apkUri = Uri.parse(url);
                Intent intent = new Intent(Intent.ACTION_VIEW, apkUri);
                context.startActivity(intent);
            } else if (url.startsWith("http")) {
                webView.loadUrl(url);
            } else {
                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                if (isInstall(context, intent)) {
                    context.startActivity(intent);
                }
            }
        }
        return true;
    }

    // 判断app是否安装
    private boolean isInstall(Context context, Intent intent) {
        return context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
    }
}
四、WebChromeClient封装实现类WebChromeClientImpl
/**
 * H5打开相机相册的回调监听
 * 进度条的回调监听
 */

public class WebChromeClientImpl extends WebChromeClient {
    // WebView打开相机相册的请求码
    public static final int FILE_REQUEST_CODE = 0x011;
    /**
     * 进度条的回调监听
     */
    private OnWebChromeListener onWebChromeListener;

    /**
     * 打开相册 本地文件等等
     */
    private ValueCallback uploadFile;
    private ValueCallback uploadFiles;
    private Activity mActivity;

    public WebChromeClientImpl(Activity activity) {
        mActivity = activity;
    }

    /**
     * 进度发生改变
     */
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        if (onWebChromeListener != null) {
            onWebChromeListener.onProgressChanged(view, newProgress);
        }
    }

    /**
     * 接收到标题
     */
    @Override
    public void onReceivedTitle(WebView view, String title) {
        if (onWebChromeListener != null) {
            onWebChromeListener.onReceivedTitle(view, title);
        }
    }

    // For Android 3.0+
    public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
        handleFileChooser(uploadMsg, null);
    }

    // For Android < 3.0
    public void openFileChooser(ValueCallback uploadMsg) {
        handleFileChooser(uploadMsg, null);
    }

    // For Android  > 4.1.1
    @Override
    public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) {
        handleFileChooser(uploadMsg, null);
    }

    // For Android  >= 5.0
    @Override
    public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) {
        handleFileChooser(null, filePathCallback);
        return true;
    }

    /**
     * 打开相册 本地文件等等
     */
    private void handleFileChooser(ValueCallback uploadMsg, ValueCallback filePathCallback) {
        if (mActivity == null || mActivity.isFinishing()) {
            return;
        }
        uploadFile = uploadMsg;
        uploadFiles = filePathCallback;
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        mActivity.startActivityForResult(Intent.createChooser(intent, "请选择"), FILE_REQUEST_CODE);
    }

    /**
     * Activity回调处理
     */
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        // 处理相机相册选择
        if (resultCode == Activity.RESULT_OK) {
            switch (requestCode) {
                case FILE_REQUEST_CODE:
                    if (null != uploadFile) {
                        Uri result = data == null || resultCode != Activity.RESULT_OK ? null : data.getData();
                        uploadFile.onReceiveValue(result);
                        uploadFile = null;
                    }
                    if (null != uploadFiles) {
                        Uri result = data == null || resultCode != Activity.RESULT_OK ? null : data.getData();
                        uploadFiles.onReceiveValue(new Uri[]{result});
                        uploadFiles = null;
                    }
                    break;
            }
        } else if (resultCode == Activity.RESULT_CANCELED) {
            if (null != uploadFile) {
                uploadFile.onReceiveValue(null);
                uploadFile = null;
            }
            if (uploadFiles != null) {
                uploadFiles.onReceiveValue(null);
                uploadFiles = null;
            }
        }
    }


    // 页面标题、加载进度回调监听接口
    public interface OnWebChromeListener {
        void onReceivedTitle(WebView view, String title);

        void onProgressChanged(WebView view, int newProgress);
    }

    public void setOnWebChromeListener(OnWebChromeListener onWebChromeListener) {
        this.onWebChromeListener = onWebChromeListener;
    }

}

代码有点多,但无非就是做了设置WebSettings、设置WebViewClient、设置WebChromeClient这三件事。

五、WebView在Activity的封装步骤
  1. Activity数据的传递(标题、URL),根据实际项目可以自己扩展。
  2. WebView初始化和加载页面的工具类,方便管理页面跳转等一些通用操作。
  3. Activity的使用封装。
六、Activity数据的传递(标题、URL)
/**
 * WebActivity传递参数的Bean
 */

public class WebData implements Serializable {
    public String url;
    public String title;
}
七、WebView初始化和加载页面的工具类
/**
 * WebView初始化和加载页面的工具类
 */

public class WebUtil {
    private static boolean isInit;

    private WebUtil() {
    }

    private static class Holder {
        private static final WebUtil INSTANCE = new WebUtil();
    }

    public static WebUtil getInstance() {
        return Holder.INSTANCE;
    }

    /**
     * 腾讯X5内核初始化
     */
    public void init(Context context) {
        if (context == null) {
            return;
        }
        if (isInit) {
            return;
        }
        //--搜集本地tbs内核信息并上报服务器,服务器返回结果决定使用哪个内核。
        try {
            QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {
                @Override
                public void onViewInitFinished(boolean arg0) {
                }

                @Override
                public void onCoreInitFinished() {
                }
            };
            //x5内核初始化接口
            QbSdk.initX5Environment(context.getApplicationContext(), cb);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        isInit = true;
    }

    private void loadWebPage(WebView webView, String url) {
        if (webView != null) {
            if (url.startsWith("http")) {
                webView.loadUrl(url);
            }

        } else {
            throw new NullPointerException("WebView is null!");
        }
    }

    private void loadLocalPage(WebView webView, String url) {
        loadWebPage(webView, "file:///android_asset/" + url);
    }

    public void loadPage(WebView webView, String url) {
        //如果是电话协议
        if (url.contains("tel:")) {
            callPhone(webView.getContext(), url);
            return;
        }
        if (URLUtil.isNetworkUrl(url) || URLUtil.isAssetUrl(url)) {
            loadWebPage(webView, url);
        } else {
            loadLocalPage(webView, url);
        }
    }


    private void callPhone(Context context, String uri) {
        final Intent intent = new Intent(Intent.ACTION_DIAL);
        final Uri data = Uri.parse(uri);
        intent.setData(data);
        context.startActivity(intent);
    }

    /**
     * 打开WebActivity
     */
    public void startWebActivity(Activity activity, String url) {
        startWebActivity(activity, url, null);
    }

    /**
     * 打开WebActivity
     */
    public void startWebActivity(final Activity activity, final String url, final String title) {
        // WebView初始化
        WebData data = new WebData();
        data.url = url;
        data.title = title;
        startWebActivity(activity, data);
    }

    /**
     * 打开WebActivity
     */
    public void startWebActivity(Activity activity, WebData data) {
        init(activity);
        Bundle bundle = new Bundle();
        bundle.putSerializable(WebActivity.WEB_DATA, data);
        ActivityUtil.startActivity(activity, WebActivity.class, bundle);
    }
}
八、Activity的使用封装
/**
 * 封装的WebActivity
 */

public class WebActivity extends AppActivity implements WebChromeClientImpl.OnWebChromeListener {

    public static final String WEB_DATA = "WebData";
    private FrameLayout mFlWebContainer;
    private WebViewInitImpl mWebViewInitializer;
    private WebView mWebView;
    // Title的封装对象
    private DefTitleBar mTitleBar;
    private ProgressWebView mProgressWebView;
    /**
     * JS注入的名称
     */
    private static final String JS_NAME = "appCarB";
    /**
     * 打开页面传递过来的参数
     */
    private WebData mWebData;


    @Override
    protected Object getContentLayout() {
        return R.layout.act_web;
    }

    @Override
    protected void initData(Bundle bundle) {
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
        // 获取上个页面传递过来的数据
        mWebData = (WebData) getIntent().getSerializableExtra(WEB_DATA);
        // WebView初始化对象
        mWebViewInitializer = new WebViewInitImpl(this);
        // WebView初始化
        initWebView();
    }

    @SuppressLint("JavascriptInterface")
    private void initWebView() {
        if (mWebView != null) {
            mWebView.removeAllViews();
        } else {
            mProgressWebView = new ProgressWebView(this);
            mWebView = mWebViewInitializer.initWebView(mProgressWebView.getWebView());
            mWebView.setWebViewClient(mWebViewInitializer.initWebViewClient());
            mWebView.setWebChromeClient(mWebViewInitializer.initWebChromeClient());
            // 注入JS交互
            mWebView.addJavascriptInterface(new JSEvent(this), JS_NAME);
        }
    }

    @Override
    protected void initTitle(DefTitleBar titleBar) {
        this.mTitleBar = titleBar;
        if (mTitleBar != null) {
            mTitleBar.setTitleLeftRightPadding(50);
            if (mWebData != null && !TextUtils.isEmpty(mWebData.title)) {
                mTitleBar.setTitle(mWebData.title);
            }
        }
    }

    @Override
    protected void initView(View view) {
        mFlWebContainer = findViewById(R.id.fl_web_container);
        mWebViewInitializer.setOnWebChromeListener(this);
        if (mFlWebContainer.getChildCount() > 0) {
            mFlWebContainer.removeAllViews();
        }
        mFlWebContainer.addView(mProgressWebView);
        // 加载URL
        if (mWebView != null && mWebData != null) {
            // 跳转并进行页面加载
            WebUtil.getInstance().loadPage(mWebView, mWebData.url);
        }
    }

    // 标题回调
    @Override
    public void onReceivedTitle(WebView view, String title) {
        if (mTitleBar != null) {
            if (mWebData != null && !TextUtils.isEmpty(mWebData.title)) {
                return;
            }
            mTitleBar.setTitle(title + "");
        }
    }

    // 页面加载进度回调
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        if (mProgressWebView == null) {
            return;
        }
        ProgressBar progressbar = mProgressWebView.getProgressbar();
        if (progressbar == null) {
            return;
        }
        if (newProgress == 100) {
            progressbar.setVisibility(View.GONE);
        } else {
            if (progressbar.getVisibility() == View.GONE) {
                progressbar.setVisibility(View.VISIBLE);
            }
            progressbar.setProgress(newProgress);
        }
    }


    @Override
    public void onPause() {
        if (mWebView != null) {
            mWebView.onPause();
        }
        super.onPause();
    }

    @Override
    public void onResume() {
        if (mWebView != null) {
            mWebView.onResume();
        }
        super.onResume();
    }


    @Override
    public void onDestroy() {
        if (mFlWebContainer != null && mWebView != null) {
            mWebView = null;
            mProgressWebView = null;
        }
        super.onDestroy();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (mWebView != null && (keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
            mWebView.goBack(); // 浏览网页历史记录 goBack()和goForward()
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // 处理相机相册选择
        if (mWebViewInitializer != null) {
            mWebViewInitializer.onActivityResult(requestCode, resultCode, data);
        }
    }

}
九、在其它Activity页面调用WebActivity
   WebUtil.getInstance().startWebActivity(this,"https://www.xxx.com");
  1. 测试页面效果图没有截出来。
  2. 除了和H5的JS交互未写,至此WebActivity封装完毕。
  3. WebActivity类中相关类的文章:
    打造Android通用的标题栏。
    Android Activity基类的抽取AppActivity(二)。
    WebView详细使用一(带进度的WebView)。
    WebView详细使用二(腾讯X5内核的集成)。

你可能感兴趣的:(WebView详细使用三(WebView初始化和Activity的封装))