Android 开发热更新 webview tabLayout 小技巧汇总

最近今天的任务量还是很重的,分配的有点多,并且代码量也是不少的,其实程序员不怕写代码,怕的是遇到问题无法找到解决途径。不过为之窃喜的是,今天我的一个突发灵感解决了小组三天里面临的问题,特此记录下思路

问题是什么?

1.热更新问题

阿里热更新hotfix,有明确要求,要想打出差分包,要确保AndroidManifest.xml 文件没有新增改变

Android 开发热更新 webview tabLayout 小技巧汇总_第1张图片
image.png

资源图片文件,代码,都是可以增加,但是AndroidManifest.xml 和Application 文件不能有洗新增。
那么问题就在于,最近新接到的需求是要开发大课堂项目,使用的H5 链接,Android 端使用webview加载即可,看似简单,却着实难为了一把,我们的项目里使用的 AgentWeb, AgentWeb标准里是用AgentWebViewActivity 去加载AgentWebFragment 来实现的

H5 端因为软键盘无法托起底部布局,所以求助Android端实现,经过研讨,我们的思路是,页面监听软键盘弹出和隐藏,拿到软件盘的高度,传递给js,Js 再去手动修改输入框布局,思路有了, 但是Android端这边因为AgentWeb 问题却棘手了

最终效果图:


Android 开发热更新 webview tabLayout 小技巧汇总_第2张图片
image.png

Android 开发热更新 webview tabLayout 小技巧汇总_第3张图片
image.png

为了实现这个效果,Android 端需要监听软键盘事件,拿到软键盘高度

首先是键盘工具类:

public class SoftKeyBoardListener {
    private View rootView;
    int rootViewVisibleHeight;
    private OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener;

    public SoftKeyBoardListener(Activity activity) {
        //获取activity的根视图
        rootView = activity.getWindow().getDecorView();

        //监听视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                //获取当前根视图在屏幕上显示的大小
                Rect r = new Rect();
                rootView.getWindowVisibleDisplayFrame(r);
                int visibleHeight = r.height();
                if (rootViewVisibleHeight == 0) {
                    rootViewVisibleHeight = visibleHeight;
                    return;
                }

                //根视图显示高度没有变化,可以看作软键盘显示/隐藏状态没有改变
                if (rootViewVisibleHeight == visibleHeight) {
                    return;
                }

                //根视图显示高度变小超过200,可以看作软键盘显示了
                if (rootViewVisibleHeight - visibleHeight > 200) {
                    if (onSoftKeyBoardChangeListener != null) {
                        onSoftKeyBoardChangeListener.keyBoardShow(rootViewVisibleHeight - visibleHeight);
                    }
                    rootViewVisibleHeight = visibleHeight;
                    return;
                }

                //根视图显示高度变大超过200,可以看作软键盘隐藏了
                if (visibleHeight - rootViewVisibleHeight > 200) {
                    if (onSoftKeyBoardChangeListener != null) {
                        onSoftKeyBoardChangeListener.keyBoardHide(visibleHeight - rootViewVisibleHeight);
                    }
                    rootViewVisibleHeight = visibleHeight;
                    return;
                }

            }
        });
    }

    private void setOnSoftKeyBoardChangeListener(OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        this.onSoftKeyBoardChangeListener = onSoftKeyBoardChangeListener;
    }

    public interface OnSoftKeyBoardChangeListener {
        void keyBoardShow(int height);

        void keyBoardHide(int height);
    }

    public static void setListener(Activity activity, OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        SoftKeyBoardListener softKeyBoardListener = new SoftKeyBoardListener(activity);
        softKeyBoardListener.setOnSoftKeyBoardChangeListener(onSoftKeyBoardChangeListener);
    }
}

之后是在AgentWebActivity的oncreate 生命周期方法里进行监听

 KeyboardUtils.registerSoftInputChangedListener(AgentWebActivity.this,
                new KeyboardUtils.OnSoftInputChangedListener() {
            @Override
            public void onSoftInputChanged(int height) {
                Log.i("height", "onSoftInputChanged: "+height);
            }
        });

        SoftKeyBoardListener.setListener(AgentWebActivity.this,
                new SoftKeyBoardListener.OnSoftKeyBoardChangeListener() {
                    @Override
                    public void keyBoardShow(int height) {
                        Log.i("higiht", "keyBoardShow:键盘高度" + height);
                        // int displayHeight = initScreenInfo();

                    }

                    @Override
                    public void keyBoardHide(int height) {
                        Log.i("higiht", "keyBoardShow:键盘高度" + height);
                    }
                });

        new HeightProvider(this).init().setHeightListener(new HeightProvider.HeightListener() {
            @Override
            public void onHeightChanged(int height) {
                Log.v("tag", "获取到键盘高度" + height);

            }
        });
        Log.i("生命週期A", "onCreate: =======--------------------------------");
        int i = initScreenInfo();
        Log.i("生命週期A", "onCreate: =======--------------------------------"+i);

可以看到,我用了三种方法,都没能在AgentWebActivity里监听到,但是经过测试放在别的anctivity里是可以获取到的。
那么放在Fragment里呢?也就是AgentWebFragment里?

  KeyboardUtils.registerSoftInputChangedListener(getActivity(), new KeyboardUtils.OnSoftInputChangedListener() {
            @Override
            public void onSoftInputChanged(int height) {
                Log.i("Fragmneytheight", "FragmneytheightonSoftInputChanged: " + height);
            }
        });


        SoftKeyBoardListener.setListener(getActivity(),
                new SoftKeyBoardListener.OnSoftKeyBoardChangeListener() {
                    @Override
                    public void keyBoardShow(int height) {
                        Log.i("Fragmneytheight", "keyBoardShow:键盘高度" + height);
                        // int displayHeight = initScreenInfo();

                    }

                    @Override
                    public void keyBoardHide(int height) {
                        Log.i("Fragmneytheight", "keyBoardShow:键盘高度" + height);
                    }
                });

        new HeightProvider(getActivity()).init().setHeightListener(new HeightProvider.HeightListener() {
            @Override
            public void onHeightChanged(int height) {
                Log.v("Fragmneytheight", "获取到键盘高度" + height);

            }
        });

结果同时是拿不到,没有办法,我自己新建一个WebViewActivity 用于加载网页获取软键盘高度,这种方式是可以的,但是同样遇到了问题:

问题1.Android 原生webview 无法加载网页视频,再部分手机上可以播放,在部分手机上不能播放

解决方法:

//设置加载模式为硬件支持
 mWebView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
 // 设置编码
 webSettings.setDefaultTextEncodingName("utf-8");
 webSettings.setDomStorageEnabled(true);
//注意此段代码片段A
 mWebView.getSettings().setPluginState(WebSettings.PluginState.ON);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }

尤其是上面代码块片段A部分,是我百度了很多网页,在国外论坛上找到的,这个方法确实奏效

问题2:webview网页评论和删除评论不会立即生效

解决方法:把缓存模式去掉即可

 // 设置缓存
        webSettings.setAppCacheEnabled(true);
        // 设置缓存模式,一共有四种模式
//        webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);

之后的事情就很简单了,android 在获取到软键盘弹出时,拿到高度,通知js,在软键盘关闭时,通知js,js在点击发布按钮的时候,调用Android 的方法,手动关闭软键盘,代码如下


//js点击发布,调用Android方法
 mWebView.addJavascriptInterface(new PublishData(AccountsSafeActivity.this), "Android");
/**
 * @author fanzhengguang
 */
public class PublishData {
    private Activity context;

    public PublishData(Activity context) {
        this.context = context;
    }


    @JavascriptInterface
    public void publishData() {
        //检测键盘是否还在弹起,弹起时关闭
        boolean open = KeyboardUtils.isOpen();
        if (open) {
            KeyboardUtils.close(context);
        }
    }
}
 @SuppressLint("SetJavaScriptEnabled")
    public void testJS(int softHeight, int displayHeight) {
        String num = null;
        try {
            DecimalFormat df = new DecimalFormat("0.0000");
            num = df.format((float) softHeight / displayHeight);
            Log.i("运算", "testJS: " + num);
        } catch (Exception e) {
            e.printStackTrace();
        }

        mWebView.loadUrl("javascript:showKeyboard(" + num + ")");
    }

    @SuppressLint("SetJavaScriptEnabled")
    public void closeTest() {
        mWebView.loadUrl("javascript:closeKeyboard()");
    }

Android 开发热更新 webview tabLayout 小技巧汇总_第4张图片
image.png

做到这,效果很棒,但是新的问题来了,不能热更新了!!!原因是WebViewActivity需要在AndroidManifest.xml文件里注册,这就导致hotfix无法应用补丁,为了解决这个方法,我跟组长连续奋战了一天多,着力想在AgentFragment里监听到软键盘,和js通信,结果都是无功而返,我们设置想着用Android原生页面实现评论列表和评论回复功能
一直到今天上午,我去卫生间,脑袋里突然冒出来一个灵感,既然不能新增页面,那我在原先现有的页面里实现WebViewActivity的功能不就行了吗
不得不说,这个方法真的很妙,我这样做了,确实可以,开心的不得了,很兴奋,能解决这个问题,我选择了一个AccountsSafeActivity,页面里写了两套布局,实现一个Activity 两种功能的做发,真的很棒!
Android 开发热更新 webview tabLayout 小技巧汇总_第5张图片
image.png

就这样,热更新又能正常应用,组长都说你这个家伙真聪明,我怎么没想到,哈哈,我也佩服自己,有的时候确实挺聪明的。

最后一个问题:google的tabLayout 点击的背景色怎么去除掉

image.png

就是这样一个灰色的色块,Android api里也没有说明,试了背景色前景色都是无效的,


Android 开发热更新 webview tabLayout 小技巧汇总_第6张图片
image.png

最后经过努力,终于还是找到了去除的方法:

  mEasyIndicator.setTabRippleColor(ColorStateList.valueOf(getContext().getResources().getColor(R.color.transparent)));

Ok,就记录到这里吧。
顺便说一下,在我高三的时候,我一直在想着将来做什么,后来我想了很久,还是想从事技术方面的,当时我跟室友说,不想跟人打交道,太复杂,还是做技术比较纯粹。不知不觉已经写了几年代码了,心里话,就是,做程序,写代码,真的很纯粹,很执着也很专注,能锲而不舍地研究新技术,也能专心致志地寻找程序bug,程序员人很好,就我而言,脾气很好,也很有耐心,但是也是因为从事程序行业,每天对着电脑写代码,人会很单纯,说好听的是单纯纯粹,说不好听的就是有点不成熟,这确实是行业和职业习惯导致,的确,需要成长得地方很多。
很多年前,我听人说过,要不断丰富自己,确实是这样,要多读书,不能只读工科技术类的,要人文历史情感类的丰富阅读完善自己。

I love you forevery

希望我的那个她,你能看到听到,用心感受到,我爱你。

你可能感兴趣的:(Android 开发热更新 webview tabLayout 小技巧汇总)