Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android interactive with WebView #128

Open
soapgu opened this issue Mar 28, 2022 · 0 comments
Open

Android interactive with WebView #128

soapgu opened this issue Mar 28, 2022 · 0 comments
Labels
mvvm This issue or pull request already exists 安卓 安卓

Comments

@soapgu
Copy link
Owner

soapgu commented Mar 28, 2022

  • 前言

我们知道安卓的世界WebView控件就是Chrome的实现的浏览器。
目前我们对WebView的用法还毕竟“肤浅”,只是当一个浏览器在用。我们知道对于App来说只是嵌入一个浏览器是远远不够的,类似支付宝微信等App已经在BS端做到了你中有我,我中有你的深入对接。

  • web -> app 端的交互实现

我们还是从实际项目出发也着手这方面问题,比如Web页面有个返回按钮,他已经到到最外层。在点击后,其实已经交给App去处理了,需要退出当前页面,回到堆栈上一层。要怎么实现那?

  • 实现过程

  1. 前端
<li><a onClick="window.test.back()">返回</a></li>

需要声明js到function,windows.<模块名>.<方法名>

  1. WebView

需要调用setJavaScriptEnabled和addJavascriptInterface这两个api

    webView.getSettings().setJavaScriptEnabled(true);
    public void addJavascriptInterface(Object obj, String interfaceName) {
    }

其中
ojb:JavascriptInterface的实现
interfaceName:模块名

对于JavescriptInterface的定义,需要实现back方法

    @JavascriptInterface
    public void back(){
        \\...
    }

3.结合MVVM实现
应该我们都是严格按照MVVM的架构来实现的。所以怎么“融入”?

先上粘合剂BindingAdapter

  • BindingAdapter
    @SuppressLint({"SetJavaScriptEnabled", "JavascriptInterface"})
    @BindingAdapter(value={"android:url","jsObject","jsName"},requireAll = false)
    public static void setWebViewUrl(WebView webView , String url, Object jsObject , String jsName ){
        webView.getSettings().setJavaScriptEnabled(true);
        webView.loadUrl( url );
        if( jsObject != null && jsName != null )
        webView.addJavascriptInterface( jsObject , jsName );
    }

索性和url的绑定一并收编整合了,jsObject和jsName作为可选参数

  • ViewModel
@HiltViewModel
public class MobileWebViewModel extends ObservableViewModel {

    private String url;
    private final MutableLiveData<Boolean> backSignal;

    @Inject
    public MobileWebViewModel(@NonNull Application application) {
        super(application);
        backSignal = new MutableLiveData<>(false);
    }

    @Bindable
    public String getUrl() {
        return url;
    }

    public MutableLiveData<Boolean> getBackSignal() {
        return backSignal;
    }

    public void setUrl(String url) {
        this.url = url;
        this.notifyPropertyChanged(BR.url);
    }

    @JavascriptInterface
    public void back(){
        this.backSignal.postValue(true);
    }

    public String getJsName(){
        return "test";
    }
}

直接ViewModel和JavescriptInterface合并,违和感完全没有问题

  • View
    View肯定是不能缺少的一环
<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <data>
        <variable
            name="dataContext"
            type="com.space365.mobile.viewmodels.MobileWebViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".fragments.MobileWebFragment">

        <ImageView
            android:visibility="gone"
            android:id="@+id/back_image"
            android:layout_width="28dp"
            android:layout_height="28dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:src="@drawable/arrow_left"
            android:onClick="@{()->dataContext.back()}"
            android:contentDescription="@string/web"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
        <WebView
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_marginTop="8dp"
            android:url="@{dataContext.url}"
            app:jsObject="@{dataContext}"
            app:jsName="@{dataContext.jsName}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/back_image" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

layout需要把所有绑定必须的属性和绑定适配器配合起来

  • Activity/Fragment
    作为安卓的必备组件,这算不上MVVM的部分,但是是MVVM的载体,它作为一个整体去支撑起了MVVM,是一个被“架空业务逻辑”的核心,只可意会不可言传。还是上代码吧,慢慢意会。
/**
 * A simple {@link MVVMFragment} subclass.
 * Use the {@link MobileWebFragment#newInstance} factory method to
 * create an instance of this fragment.
 */
@AndroidEntryPoint
public class MobileWebFragment extends MVVMFragment<MobileWebViewModel> {

    public MobileWebFragment() {
        super(MobileWebViewModel.class,R.layout.fragment_mobile_web, BR.dataContext);
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @return A new instance of fragment MobileWebFragment.
     */
    public static MobileWebFragment newInstance() {
        return new MobileWebFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        String url = MobileWebFragmentArgs.fromBundle(this.getArguments()).getUrl();
        this.viewModel.setUrl( "https://test.space365.live/app" + url );
        this.viewModel.getBackSignal().observe( this.getViewLifecycleOwner() , back ->{
            if( back ){
                Navigation.findNavController(view).popBackStack();
            }
        } );
    }
}

主要安卓的MVVM,每一层都“没有资格”去处理退栈操作。只有核心组件Activity/Fragment能做。所以只能勉为其难让他代劳啦。
这里退栈操作和导航相关,不详细展开了。

@soapgu soapgu added mvvm This issue or pull request already exists 安卓 安卓 labels Mar 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mvvm This issue or pull request already exists 安卓 安卓
Projects
None yet
Development

No branches or pull requests

1 participant