Android(kotlin)与Js互调最全版本

H5示例代码

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" charset="utf-8"/>
    <script type="text/javascript">

        //加购
        function addcart(){

            let goodsModel = {
                "inventory" : 100,
                "name": "12112112121",
            }

                //path是js交互的协议路径
            var message = {
                'path' : 'add_cart_function_native',
                'params' : {"selectSku":6452,"goodsModel":goodsModel},
            };
            postMessage(message);
            
        }
        //发起网络请求
        function requestData(){
        }
        //埋点数据
        function tranceLogAction(){

            var message = {
                path : "trace_log_function_native",
                params :  {
                    dpType :"home_page",
                    eventType :"advertise",
                    type :"click",
                    tranceLogParams : {
                        page :1,
                        position :2
                    }
                }
            };
            postMessage(message);
            alert("上传埋点成功");

        }
        //打开新页面
        function openPage(){

            var message = {
                'path' : "open_control_native",
                'params' : {
                    "deepLink":"xxx",
                    "deepLinkParam": {}
                },
            };
            postMessage(message);

        }

        //购物车商品数量
        function cartNumber(){

            window.cacheResult = function(result){

                let p = JSON.parse(result);
                if (p.code == 200){
                    alert("购物车数量" + JSON.stringify(p.params["carGoodsNum"]));   
                }
            }
            let list = ["carGoodsNum"]
            var message = {
                'path' : "get_cache_function_native",
                'params' : {
                    "callback":"cacheResult(params)",
                    "cacheNameList": list
                },
            };
            postMessage(message);
        }


        function getToken(){

            window.observeToken = function(result){
                let p = JSON.parse(result);
                if (p.code == 200){
                    alert(p.params.access_token);   
                    return "p.params.access_token"
                }
            }
            var message = {
                'path' : "user_token_function_native",
                'params' : {"callback":"observeToken(params)"},
            };
            postMessage(message);

        }


        function postMessage(message){
             var system = isIosOrAndroid()
            if (system == 1) {
                // 安卓
                window.local_android.setMessage(JSON.stringify(message));
            }else if (system == 2) {
                // iOS
                window.webkit.messageHandlers.local_ios.postMessage(JSON.stringify(message));
            }
        }


        //判断安卓或者iOS系统
        function isIosOrAndroid() {
            var u = navigator.userAgent
            var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //android终端
            if (isAndroid) {
                return 1
            }
            var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
            if (isiOS) {
                return 2
            }
            return 0
        }
    </script>
    
    <title></title>
</head>
<body>
    <p align="center"> <input style="font-size: 18px;" type="button" value="快速加购" onClick="addcart()"></p>
    <p align="center"> <input style="font-size: 18px;" type="button" value="获取登录态" onClick="getToken()"></p>
    <p align="center"> <input style="font-size: 18px;" type="button" value="获取购物车数量" onClick="cartNumber()"></p>
    <p align="center"> <input style="font-size: 18px;" type="button" value="埋点" onClick="tranceLogAction()"></p>
    <p align="center"> <input style="font-size: 18px;" type="button" value="网络请求" onClick="requestData()"></p>
    <p align="center"> <input style="font-size: 18px;" type="button" value="打开新页面" onClick="openPage()"></p>
</body>
</html>

android代码(基类)

abstract class BaseWebViewActivity : BaseAppActivity() {

    lateinit var activityWebView : WebView
    lateinit var commonbase_activity_appbar_left:ImageView


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.commonbase_activity_web_view)
        activityWebView = findViewById(R.id.activityBaseWebView)
        commonbase_activity_appbar_left=activityWebViewTitleInclude.findViewById(R.id.commonbase_activity_appbar_left)
        setWebWs()
    }


    @SuppressLint("JavascriptInterface")
    private fun setWebWs() {
        val ws: WebSettings? = activityWebView?.settings
        //这写注释先不要删掉
        //ws.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);//自适应屏幕  //导致4.4以下摇钱树只显示背景和标题
        //      ws.setLoadWithOverviewMode(true);//自适应屏幕,使用后字体变小,
        //      ws.setAllowFileAccess(false);// 设置允许访问文件数据
        //      ws.setJavaScriptCanOpenWindowsAutomatically(false);//自动打开窗口
//              ws.setAppCacheEnabled(false);
        //      ws.setSupportZoom(true);// 设置支持缩放
        //      ws.setBuiltInZoomControls(true);// 设置支持缩放
        //      ws.setDisplayZoomControls(false);//显示缩放按
        ws?.setAllowFileAccess(true);// -> 是否允许访问文件
        ws?.setDomStorageEnabled(false); //-> 是否节点缓存
        ws?.setDatabaseEnabled(false);// -> 是否数据缓存
        ws?.setAppCacheEnabled(false);// -> 是否应用缓存
        ws?.loadWithOverviewMode = true
        ws?.builtInZoomControls = true
        ws?.displayZoomControls = false
        //? ws.setAllowFileAccessFromFileURLs(false);
        //? ws.setAllowFileAccessFromFileURLs(false);
        ws?.useWideViewPort = true //图片被缩放后显示不全的问题
        ws?.javaScriptEnabled = true
        ws?.savePassword = false
        ws?.blockNetworkImage = false
        ws?.loadsImagesAutomatically = true

        var oldUA = ws?.userAgentString
        //UA都是跟h5约定好提供什么参数
        val addAgent =
            " AppName/(${ChicvUserAgentDataManager.getAppName()}) LanguageId/($language_id) Language/($language_code) Currency/($currency_code) CurrencyId/($country_id) WappBrowser/1.2.6 ChannelId/(1) PlatformId/(1) LastLoginTime/ Version/(${
                getVersionName(MyApplication.getInstance())
            }) SystemVersion/(${ChicvUserAgentDataManager.getOsVersion()})"
        ws?.userAgentString = oldUA + addAgent

        val timecurrentTimeMillis = System.currentTimeMillis()
        val sign = MD5Util.getMD5("SECRET")
        val language_id = language_id
        val language_code = language_code
        val currency_code = currency_code
        val country_id = currencyCountry_id.toString()

        activityWebView?.addJavascriptInterface(this, "local_android");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //5.0以上默认不允许http和https混合模式, 需手动开启
            ws?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
        }
//        activityWebView.webChromeClient = BaseWebChromeClient()
//        activityWebView.webViewClient = BaseWebViewClient(activityWebViewProgressbar)
        //设置cookie
        syncCookie()
        val token = if (GlobalFunc.hasLogin()) GlobalFunc.getAccountToken() else ""
        var cookies = if (token.isNullOrEmpty()) "currency=$currency_code;language=$language_id;language-code=$language_code" else "access_token=$token;currency=$currency_code;language=$language_id;language-code=$language_code"
        //设置header,给后端使用
        val headerMap = mapOf(
            "x-origin-client" to "Android",
        )
        if (getLoadUrl() != null) activityWebView?.loadUrl(getLoadUrl(), headerMap)
    }

    protected abstract fun getLoadUrl(): String

    open fun syncCookie(): Boolean {
        var url = getLoadUrl()
        val cookieManager = CookieManager.getInstance()
        cookieManager.setAcceptCookie(true)
        cookieManager.removeSessionCookies(null)
        cookieManager.removeAllCookies(null)
        val token = if (GlobalFunc.hasLogin()) GlobalFunc.getAccountToken() else ""
        val currency = currency_code
        val language = language_id
        var cookies = if (token.isNullOrEmpty()) "currency=$currency;language=$language;language-code=$language_code" else "access_token=$token;currency=$currency;language=$language;language-code=$language_code"
        url.logW("currency_code2")
        cookies.logW("currency_code2")
        cookieManager.setCookie(url, cookies)
        val newCookie = cookieManager.getCookie(url)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            val cookieSyncManager = CookieSyncManager.createInstance(mContext)
            cookieSyncManager.sync()
        } else {
            cookieManager.flush()
        }
        return if (!newCookie.isNullOrEmpty()) false else true
    }


}

子类

class SpecialWebViewActivity : BaseWebViewActivity() {

    override val pageTag: String
        get() = TraceDpType.WebView.value

    var isShowCartBtn = 0//0 hidden 1 show
    var isShowTopBtn = 0//0 hidden 1 show
    var goodsDetailsReturRl : RelativeLayout? = null
    var merchandiseCustomerRl : RelativeLayout? = null
    var commonbase_num_bg : RelativeLayout? = null
    var commonbase_num : TextView? = null

    override fun getLoadUrl(): String {
        var dataMap = intent.getSerializableExtra("param") as Map<String, Objects>?
        if (!dataMap.isNullOrEmpty() && dataMap!!.containsKey(GlobalVariable.WEB_URL)) {
            return dataMap!!.get(GlobalVariable.WEB_URL) as String
        } else return ""
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setWebViewClient()
        setUI()
        EventBusUtil.register(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        EventBusUtil.unregister(this)
    }

    fun setUI() {
        goodsDetailsReturRl = findViewById(R.id.goodsDetailsReturWebViewRl)
        merchandiseCustomerRl = findViewById(R.id.merchandiseCustomerRl)
        commonbase_num_bg = findViewById(R.id.commonbase_num_bg)
        commonbase_num = findViewById(R.id.commonbase_num)
        merchandiseCustomerRl?.setOnClickListener {

            if (LocalAppSettings.localProviderSettingsData.value!!.cart_need_login == "0") {
                DeepPathLinkUtil.deepPathHome(
                    this,
                    DeepPath.cart,
                    "cart",
                    "",
                    null,
                    ""
                )
            } else {
                GlobalFunc.isLoginAndGo(mContext) {
                    if (it) {
                        DeepPathLinkUtil.deepPathHome(
                            this,
                            DeepPath.cart,
                            "cart",
                            "",
                            null,
                            ""
                        )

                    }
                }
            }
        }

        goodsDetailsReturRl?.setOnClickListener {
            scrollToTop(true)
        }

        //判断sku有没有更新  以及存储sku信息
        val cartNum = UserSPUtils.getInstance().getString(GlobalVariable.CARTNUM)
        cartNum.logW("cartNum")
        if (!TextUtils.isEmpty(cartNum) && "0" != cartNum) {
            commonbase_num_bg?.visibility = View.VISIBLE
            commonbase_num?.text = Tools.change99(cartNum)
        } else {
            commonbase_num_bg?.visibility = View.INVISIBLE
        }
    }

    fun setWebViewClient() {
        val webChromeClient = object : WebChromeClient() {
            override fun onProgressChanged(view: WebView, newProgress: Int) {
                super.onProgressChanged(view, newProgress)

            }

            override fun onReceivedTitle(view: WebView, title: String) {
                super.onReceivedTitle(view, title)
                //这里面可以赋值给到title
                title.logW("qqqqqqqq")
                setWebViewTitle(title,view)
            }

            override fun onJsAlert(
                view: WebView?,
                url: String?,
                message: String?,
                result: JsResult?
            ): Boolean {
                ToastUtils.showShort("123")
                return super.onJsAlert(view, url, message, result)
            }

            override fun onJsPrompt(
                view: WebView?,
                url: String?,
                message: String?,
                defaultValue: String?,
                result: JsPromptResult?
            ): Boolean {
                ToastUtils.showShort("1234")
                return super.onJsPrompt(view, url, message, defaultValue, result)
            }
        }
        val webViewClient = object : WebViewClient() {
            override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                super.onPageStarted(view, url, favicon)
            }

            override fun onPageFinished(view: WebView?, url: String?) {
                val cookieManager = CookieManager.getInstance()
                cookieManager.getCookie(url).logW("currency_code3")
                super.onPageFinished(view, url)
            }

            override fun onReceivedSslError(
                view: WebView?,
                handler: SslErrorHandler?,
                error: SslError?
            ) {
                super.onReceivedSslError(view, handler, error)
                handler?.proceed()
            }
        }
        activityWebView?.webChromeClient = webChromeClient
        activityWebView?.webViewClient = webViewClient
    }

    @JavascriptInterface
    fun setMessage(msg: String) {

        /*
        *add_cart_function_native  > GlobalVariable.SpecialPath.addCart.value 快速加购
        *user_token_function_native 获取登录态
        * webView.loadUrl("observeToken('')"); */
        LogUtils.e("qqqqqqqq", msg)
        val specialModel = JsonUtils.StringToObject(msg, SpecialModelDTO::class.java)
        specialModel.toString().logW()


        if (!specialModel.path.isNullOrEmpty() && specialModel.path == GlobalVariable.SpecialPath.addCart.value) {//加入购物车
            specialModel.params.let {
                it.handle.let { it1 ->
                    goodsListDetails(it1, it.selectSku)
                }
            }
        } else if (!specialModel.path.isNullOrEmpty() && specialModel.path == GlobalVariable.SpecialPath.token.value) {//获取token
            val tokenStr = if (GlobalFunc.hasLogin()) GlobalFunc.getAccountToken() else "123"
            var tokenMap: Map<String, String>? = null
            tokenStr?.let { tokenMap = mapOf<String, String>("access_token" to it) }
            var json = JSONObject()
            json.put("code", 200)
            json.put("message", "成功")

            val param = tokenMap?.let {
                json.put("params", tokenMap)
//                mapOf<String,Any>("code" to 200, "message" to "成功", "params" to it.toString())
            }
//            activityWebView?.loadUrl("javascript:observeToken('${param.toString()}')");

            var result = "服务器返回的数据"

            //调用js方法必须在主线程
            callBackFunction(specialModel.params.callback, json.toString())

        } else if (!specialModel.path.isNullOrEmpty() && specialModel.path == GlobalVariable.SpecialPath.cartGoodsNum.value) {//购物车数量
            val cartNum = UserSPUtils.getInstance().getString(GlobalVariable.CARTNUM)
            var tokenMap: Map<String, String>? = null
            var json = JSONObject()
            json.put("code", 200)
            json.put("message", "成功")
            json.put("params", mapOf("carGoodsNum" to cartNum.toInt()).toString())

            callBackFunction(specialModel.params.callback, json.toString())
        } else if (!specialModel.path.isNullOrEmpty() && specialModel.path == GlobalVariable.SpecialPath.traceLog.value) {//埋点
            var tranceLogParams: TranceLogParams? = specialModel?.params?.tranceLogParams

        } else if (!specialModel.path.isNullOrEmpty() && specialModel.path == GlobalVariable.SpecialPath.openView.value) {//打开新界面
            specialModel.params.deepLink?.apply {
                var retMap = UriParams.getUriParams(this)
                DeepPathLinkUtil.deepPathHome(mContext, this, null, null, retMap, null)
            }

        }
        else if (!specialModel.path.isNullOrEmpty() && specialModel.path == GlobalVariable.SpecialPath.floatCart.value) {//展示购物车浮窗/置顶按钮
            isShowTopBtn =
                if (specialModel.params.alertType == 2 && specialModel.params.isShow == 1) 1 else 0
            isShowCartBtn =
                if (specialModel.params.alertType == 1 && specialModel.params.isShow == 1) 1 else 0

            merchandiseCustomerRl?.visibility = if (isShowCartBtn == 1) View.VISIBLE else View.INVISIBLE
            goodsDetailsReturRl?.visibility = if (isShowTopBtn == 1) View.VISIBLE else View.GONE
            commonbase_num_bg?.visibility = if (isShowCartBtn == 1) View.VISIBLE else View.INVISIBLE
        }else if (!specialModel.path.isNullOrEmpty() && specialModel.path == GlobalVariable.SpecialPath.jsFunction.value) {//强制跑脚本(转ar模式)
            MyCoroutineScope().runWithMain {
                activityWebView.loadUrl("javascript:$('html').addClass('rtl-wrapper')")
            }
            callBackFunction(specialModel.params.jsString, "")
        }
    }

    private fun callBackFunction(methodName: String, message: String?) {
        MyCoroutineScope().runWithMain {
            var method = methodName.replace("params", "'$message'")
            activityWebView.loadUrl("javascript:$method")
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onCartNumEvent(event: CartNumEvent?) {
        if (event == null) return
        commonbase_num_bg?.visibility = if (event.cartNum == 0) View.INVISIBLE else View.VISIBLE
        commonbase_num?.text = Tools.change99(event.cartNum)// event.cartNum.toString() + ""
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
            if (keyCode == KeyEvent.KEYCODE_BACK && activityWebView.canGoBack()) {
                activityWebView.goBack()// 返回前一个页面
                return true
            }
        return super.onKeyDown(keyCode, event)
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,408评论 4 371
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,690评论 2 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,036评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,726评论 0 221
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,123评论 3 296
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,037评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,178评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,964评论 0 213
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,703评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,863评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,333评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,658评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,374评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,195评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,988评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,167评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,970评论 2 279

推荐阅读更多精彩内容