现在很多 App 里都内置了 Web 网页,比如电商平台淘宝、京东等。那么这种该如何实现呢?其实这是 Android 里一个叫 WebView 的组件实现的。下面将介绍 WebView 的实例。下面的实例是以组件化为基础搭建的。
新建项目 WebView,然后对整个项目做统一的版本管理。在 project 下的 build.gradle 里添加如下代码。
修改 app 下的build.gradle 代码如下,即将统一管理的版本引进来,同时添加对 viewBinding 的使用。使用 viewBinding 就是为了避免繁琐的 findViewById() 操作。
添加 WebView module模块,用来实现 WebView 相关功能。File --> new --> new module --> Android Library
对 WebView 模块的 build.gradle 做与 app 模块相同的版本管理,并添加 viewBinding。
添加网络访问权限
这是前提!在WebView 模块里的 AndroidManifest.xml 里添加访问网络的权限。
<uses-permission android:name="android.permission.INTERNET"/>
在 WebView 模块里新建 WebViewActivity.java,然后对应的 xml 布局如下:
<?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"
tools:context=".WebViewActivity">
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
WebViewActivity,java 主要实现网页的打开,这里以 https://www.baidu.com 练习。代码如下
public class WebViewActivity extends AppCompatActivity {
private ActivityWebViewBinding mBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = ActivityWebViewBinding.inflate(LayoutInflater.from(this));
setContentView(mBinding.getRoot());
//TODO 设置可以与 JS 交互,因为百度网页代码是有js代码的
mBinding.webView.getSettings().setJavaScriptEnabled(true);
// LoadUrl 打开对应网址的内容
mBinding.webView.loadUrl("https://www.baidu.com");
}
}
注意:这里的网址以https开头的,如果是http的话,需要在 WebView模块的 AndroidManifest.xml 里添加 android:usesCleartextTraffic="true"。
app 模块下的 MainActivity.java 主要实现点击跳转到 WebViewActivity 的功能。
public class MainActivity extends AppCompatActivity {
ActivityMainBinding mBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = ActivityMainBinding.inflate(LayoutInflater.from(this));
setContentView(mBinding.getRoot());
mBinding.openWebView.setOnClickListener(v -> {
startActivity(new Intent(this, WebViewActivity.class));
});
}
}
注意:MainActivity.java 与 WebViewActivity.java 是位于两个 module 下的 java 代码,是不能直接调用的。要在 app 模块里的 MainActivity 里调用 WebView 模块里的 WebViewActivity,需要在 app 模块的 build.gradle 里添加 api project(":WebView"),添加对 WebView 模块的引用。
到此,通过上面的代码,我们就简单的实现了通过 WebView 打开网页的功能!
我们要通过组件化实现上面的功能,上面 MainActivity 中的调用明显不是组件化,且也不能这么写代码。WebView模块是一个单独的组件,而组件之间是互不交互的,所以要通过组件间通信来完成。常见的组件间通信有 arouter、cc 以及 auto service,我们这里将使用 auto service 来完成。
使用 auto service 我们首先要加入一个依赖。
在 project 下的 build.gradle 里添加如下代码
googleAutoServiceDependency ='com.google.auto.service:auto-service:1.0.1'
在 WebView 模块的 build.dradle 里添加如下代码,把 auto service 加上
annotationProcessor rootProject.googleAutoServiceDependency
implementation rootProject.googleAutoServiceDependency
要满足组件化的需求,WebView 里打开网页的操作我们要给其它组件或者 app 模块使用,所以我们要在 common 层写一个接口,然后在 WebView 模块把这个接口实现,其它组件就能通过 common 层的接口在 WebView 模块中找到实现,这种方法称为接口下沉。
我们新建一个 moduel 为 common,并修改版本操作。
然后创建一个 IWebViewInterface 的接口
public interface IWebViewInterface {
void startWebViewActivity(Context context, String url, String title);
}
在 WebView 模块中,创建一个 WebViewserviceImpl.java 来实现 IWebViewInterface 接口,实现到 WebViewActivity 的跳转。
在 WebView 模块中的build.gradle 里添加对 common 层的依赖。
api project(":common")
WebViewserviceImpl.java 的代码如下。Constants 是一个存放静态常量的类。
//TODO 添加注解,说明 WebViewServiceImpl 实现了 IWebViewService 接口的
@AutoService(IWebViewInterface.class)
public class WebViewserviceImpl implements IWebViewInterface {
@Override
public void startWebViewActivity(Context context, String url, String title) {
Intent intent = new Intent(context, WebViewActivity.class);
intent.putExtra(Constants.URL, url);
intent.putExtra(Constants.TITLE, title);
context.startActivity(intent);
}
}
最后,在 app 模块完成对IWebViewInterface 接口的调用,app 模块也要用到 auto service,所以也要添加依赖:
annotationProcessor rootProject.googleAutoServiceDependency
implementation rootProject.googleAutoServiceDependency
MainActivity.java 的代码修改如下
public class MainActivity extends AppCompatActivity {
ActivityMainBinding mBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = ActivityMainBinding.inflate(LayoutInflater.from(this));
setContentView(mBinding.getRoot());
mBinding.openWebView.setOnClickListener(v -> {
//startActivity(new Intent(this, WebViewActivity.class));
// TODO 使用 auto service 完成跳转
IWebViewInterface iWebViewInterface = ServiceLoader.load(IWebViewInterface.class).iterator().next();
if (iWebViewInterface != null) {
iWebViewInterface.startWebViewActivity(this, "https://www.baidu.com", "百度");
}
});
}
}
上面代码里的 ServiceLoader.load(IWebViewInterface.class).iterator().next(); 这一句可以包装一下,应该放到 base 层,所以我们又要新建一个 base module,来完成对这句代码的封装。
同样对 base 模块下的 build.gradle 也进行统一的版本管理
在 base 层新建 AutoServiceLoader.java 实现对 ServiceLoader.load(IWebViewInterface.class).iterator().next() 的封装
public class AutoServiceLoader {
// 其它类是不能 new 的
private AutoServiceLoader(){
}
// 泛型方法 TODO 传进来的是 S 类 , 返回去的还是 S 类
public static <S> S load(Class<S> service){
try {
return ServiceLoader.load(service).iterator().next();
}catch (Exception e){
return null;
}
}
}
在 common 层的build.gradle 里添加对 base 层的依赖
api project(":base")
以 api 添加的模块之间的依赖是向下传递的,即 app 中依赖 WebView, WebView 中依赖 common, common 中依赖 base,那么 app 中就能依赖到 common 和 base。所以 app 模块中的 MainActivity 就能调用 base 层的 AutoServiceLoader 类。
修改 MainActivity.java 里的代码如下
至此,我们通过组件化完成了 WebView 的使用了!
完成 Demo
链接:https://pan.baidu.com/s/1B09-JNuqlDyoh3FB4BXbRw
提取码:gxpb