Android WebView 音频播放控制 & 视频全屏播放

需求 1

播放是没有问题的,主要是退出页面,或者当前页面 onPause 时,要停止音乐播放

解决方案

找了好久解决方案,以下仅就我所用到且有用的,做记录:
自定义 WebView,先实例化,注册监听

    private fun audioWebViewControl() {
        audioManager = context?.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        listener = AudioManager.OnAudioFocusChangeListener {
//            when (it) {
//                AudioManager.AUDIOFOCUS_LOSS -> ToastUtils.showShortToast(context, "loss")
//                AudioManager.AUDIOFOCUS_GAIN -> ToastUtils.showShortToast(context, "gain")
//            }
        }
    }

争夺音频输出的控制权(这是WebView中的 onPause 方法)

    override fun onPause() {
        var i = 0
        do {
            val result = audioManager?.requestAudioFocus(listener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
            if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
                break
            }
            i++
        } while (i < 10)
        super.onPause()
    }

需求 2

要求富文本中的视频可以全屏播放,调用的是 WebView 内核原生的视频播放器

遇到的小插曲
  1. PC可以正常全屏播放,而Android端不展示 全屏按钮
    private lateinit var rootView: FrameLayout
    fun initView(content: String, rootView: FrameLayout) {
        initView(content, null)
        this.rootView = rootView
    }
 webChromeClient = (object : WebChromeClient() {
            override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
                super.onShowCustomView(view, callback)
                customView = view
                customViewCallback = callback
//                ToastUtils.showShortToast(context, "show")
                visibility = View.GONE
                rootView.addView(customView)
            }

            override fun onHideCustomView() {
                super.onHideCustomView()
                if (customViewCallback != null) {
//                    ToastUtils.showShortToast(context, "hide")
                    customViewCallback!!.onCustomViewHidden()
                    visibility = View.VISIBLE
                    rootView.removeView(customView)
                }
            }
        })

或者

 webChromeClient = (object : WebChromeClient() {
            override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
                super.onShowCustomView(view, callback)
                customView = view
                customViewCallback = callback
                rootView.addView(customView)

            }

            override fun onHideCustomView() {
                super.onHideCustomView()
                if (customViewCallback != null) {
                    rootView.removeView(customView)
                }
            }
        })

设置完成就可以展示出来了,需要注意的是:
一定要先实例化 WebChromeClient,否则有可能仍不展示

        webChromeClient = WebChromeClient()

小技巧

可能上述已经解决大部分问题。但是我遇到了特殊情况:

页面结构

现在我在最底层,也就是单个子任务页,其父容器也就是ViewPage,未铺满全屏且自适应高度。当我将最外层布局 传入时,就将ViewPage撑了1.5个屏左右,且向上滑动还有其他内容区。

怎么能让视频全屏的时候浮在所有的view上面,而不随着全屏拉伸内容区呢?
即使是在多层嵌套的最底层。

解决

灵感来自传入的类型 FrameLayout
我忽然意识到整个View树的最顶端就是 FrameLayout ,也就是 DecorView

    fun initView(content: String, rootView: FrameLayout) {
        initView(content, null)
        this.rootView = rootView
    }

于是,问题迎刃而解,所谓 以无厚入有间,恢恢乎其于游刃必有余地矣。

    wv_task_sub_topic.initView(it, activity!!.window.decorView as FrameLayout)

项目中用到的地方

//  设置题干富文本
     subtaskEntity.description?.let {
//   需要在父容器中展示,而不是当前view,所以传入 DecorView 会让全屏播放脱离父view的束缚
         wv_task_sub_topic.initView(it, activity!!.window.decorView as FrameLayout)
     }

传入 DecorView 会让全屏播放脱离父view的束缚,这是没有错的,但是又遇到了新的问题。

后续补充(2018/10/09)

忽略了个别机型的 Navigation Bar (导航栏)。
DecorView 是包含 Navigation Bar (导航栏) 的,
**全屏后会出现被 导航栏 遮挡 退出全屏的按钮,而无法退出全屏。
固然可以通过各种测量来解决导航栏的问题,但我们应从根源上解决问题!

传入一个不包含导航栏的父View不就可以了?这就是答案!

Window的RootView,表示当前应用程序的有效高度。即去掉状态栏和导航栏后的高度;

// 获取方式
activity!!.window.findViewById(Window.ID_ANDROID_CONTENT)

最后修改代码如下:

//        设置题干富文本
        subtaskEntity.description?.let {
            //            需要在父容器中展示,而不是当前view,所以传入 DecorView 会让全屏播放脱离父view的束缚
//            wv_task_sub_topic.initView(it, activity!!.window.decorView as FrameLayout)
            wv_task_sub_topic.initView(it, activity!!.window.findViewById(Window.ID_ANDROID_CONTENT) as FrameLayout)
        }

附自定义WebView代码

/**
 * <pre>
 *     author : jake
 *     time   : 2018/07/31
 *     function   :  webview 简装
 *     version: 1.0
 * </pre>
 */
class TaskTitleWebView(context: Context?, attrs: AttributeSet? = null) : WebView(context, attrs) {

    private lateinit var rootView: FrameLayout
    private var customViewCallback: WebChromeClient.CustomViewCallback? = null
    private var customView: View? = null

    private var audioManager: AudioManager? = null
    private lateinit var listener: AudioManager.OnAudioFocusChangeListener


    fun initView(content: String) {
        initView(content, null)
    }

    fun initView(content: String, rootView: FrameLayout) {
        initView(content, null)
        this.rootView = rootView
    }

    @SuppressLint("SetJavaScriptEnabled")
    fun initView(content: String, callBack: WebViewClientCallBack?) {
        audioWebViewControl()
        setBackgroundColor(0) //设置背景色
        background.alpha = 0 //设置填充透明度(布局中一定要设置background,不然getbackground会是null)

        val webSettings = settings
        webSettings.javaScriptEnabled = true
        webSettings.builtInZoomControls = true
        webSettings.displayZoomControls = false
        scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY //取消滚动条白边效果
        webViewClient = WebViewClient()
        webChromeClient = WebChromeClient()
        webSettings.defaultTextEncodingName = "UTF-8"
        webSettings.blockNetworkImage = false
//        loadData(content, "text/html", "UTF-8")
        loadData(content, "text/html; charset=UTF-8", null)


        webChromeClient = (object : WebChromeClient() {
            override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
                super.onShowCustomView(view, callback)
                customView = view
                customViewCallback = callback
//                ToastUtils.showShortToast(context, "show")
                visibility = View.GONE
                rootView.addView(customView)
            }

            override fun onHideCustomView() {
                super.onHideCustomView()
                if (customViewCallback != null) {
//                    ToastUtils.showShortToast(context, "hide")
                    customViewCallback!!.onCustomViewHidden()
                    visibility = View.VISIBLE
                    rootView.removeView(customView)
                }
            }
        })

    }

    override fun onPause() {
        var i = 0
        do {
            val result = audioManager?.requestAudioFocus(listener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
            if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
                break
            }
            i++
        } while (i < 10)
        super.onPause()
    }



    private fun audioWebViewControl() {
        audioManager = context?.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        listener = AudioManager.OnAudioFocusChangeListener {
//            when (it) {
//                AudioManager.AUDIOFOCUS_LOSS -> ToastUtils.showShortToast(context, "loss")
//                AudioManager.AUDIOFOCUS_GAIN -> ToastUtils.showShortToast(context, "gain")
//            }
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容