Android(kotlin)與Js互調(diào)最全版本

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交互的協(xié)議路徑
            var message = {
                'path' : 'add_cart_function_native',
                'params' : {"selectSku":6452,"goodsModel":goodsModel},
            };
            postMessage(message);
            
        }
        //發(fā)起網(wǎng)絡請求
        function requestData(){
        }
        //埋點數(shù)據(jù)
        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);

        }

        //購物車商品數(shù)量
        function cartNumber(){

            window.cacheResult = function(result){

                let p = JSON.parse(result);
                if (p.code == 200){
                    alert("購物車數(shù)量" + 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系統(tǒng)
        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="獲取登錄態(tài)" onClick="getToken()"></p>
    <p align="center"> <input style="font-size: 18px;" type="button" value="獲取購物車數(shù)量" 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="網(wǎng)絡請求" 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以下?lián)u錢樹只顯示背景和標題
        //      ws.setLoadWithOverviewMode(true);//自適應屏幕,使用后字體變小,
        //      ws.setAllowFileAccess(false);// 設置允許訪問文件數(shù)據(jù)
        //      ws.setJavaScriptCanOpenWindowsAutomatically(false);//自動打開窗口
//              ws.setAppCacheEnabled(false);
        //      ws.setSupportZoom(true);// 設置支持縮放
        //      ws.setBuiltInZoomControls(true);// 設置支持縮放
        //      ws.setDisplayZoomControls(false);//顯示縮放按
        ws?.setAllowFileAccess(true);// -> 是否允許訪問文件
        ws?.setDomStorageEnabled(false); //-> 是否節(jié)點緩存
        ws?.setDatabaseEnabled(false);// -> 是否數(shù)據(jù)緩存
        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約定好提供什么參數(shù)
        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 獲取登錄態(tài)
        * 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 = "服務器返回的數(shù)據(jù)"

            //調(diào)用js方法必須在主線程
            callBackFunction(specialModel.params.callback, json.toString())

        } else if (!specialModel.path.isNullOrEmpty() && specialModel.path == GlobalVariable.SpecialPath.cartGoodsNum.value) {//購物車數(shù)量
            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) {//強制跑腳本(轉(zhuǎn)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)
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末踏拜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丽旅,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機篮昧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來笋妥,“玉大人懊昨,你說我怎么就攤上這事〈盒” “怎么了酵颁?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長月帝。 經(jīng)常有香客問我躏惋,道長,這世上最難降的妖魔是什么嚷辅? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任簿姨,我火速辦了婚禮,結(jié)果婚禮上簸搞,老公的妹妹穿的比我還像新娘扁位。我一直安慰自己,他們只是感情好趁俊,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布域仇。 她就那樣靜靜地躺著,像睡著了一般寺擂。 火紅的嫁衣襯著肌膚如雪暇务。 梳的紋絲不亂的頭發(fā)上泼掠,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天孕似,我揣著相機與錄音捎迫,去河邊找鬼。 笑死头滔,一個胖子當著我的面吹牛蝠检,可吹牛的內(nèi)容都是我干的沐鼠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼叹谁,長吁一口氣:“原來是場噩夢啊……” “哼饲梭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起焰檩,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤憔涉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后析苫,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體兜叨,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年衩侥,在試婚紗的時候發(fā)現(xiàn)自己被綠了国旷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡茫死,死狀恐怖跪但,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情峦萎,我是刑警寧澤屡久,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站爱榔,受9級特大地震影響被环,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜详幽,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一蛤售、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧妒潭,春花似錦、人聲如沸揣钦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冯凹。三九已至谎亩,卻和暖如春炒嘲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背匈庭。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工夫凸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人阱持。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓夭拌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親衷咽。 傳聞我的和親對象是個殘疾皇子鸽扁,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容