APP打包的那点事

最近团队有需求将一个移动端网站打包成Android App,最初尝试过使用一些在线打包工具,但打包出来即难看又难用,所以还是撸起袖子自己干吧。需求无非是增加几个Tab栏,接入微博微信分享等社交功能,再用webview把网页加载进来,花了一点时间完成了,对常用的一些知识点做个总结。

webview的一些细节

处理页面导航

一般来说,在webview中点击一个链接之后,Android会打开一个能处理URL事件的APP,例如你默认的浏览器,如果我们想要自己去处理webview中网页的前进后退甚至更多的事情,就可以利用WebviewClient.

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient());

竟然敢叫Native App,我们自然就不会只有一个页面,所以我们需要在用户点击某些链接时跳转到新的Activity,以及在页面开始加载时显示加载动画,页面结束加载时让动画结束,此时我们可以重载WebViewClient中的方法。

private WebViewClient mClient = new WebViewClient() {
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            mRefreshLayout.setRefreshing(true);
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            if (mRefreshLayout.isRefreshing()) {
                mRefreshLayout.setRefreshing(false);
            }
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            Intent intent = new Intent(getActivity(), DetailsActivity.class);
            intent.putExtra(AppUtil.KEY_URL, url);
            startActivity(intent);
            return true;
        }
    };
}

除此之外,当然可以通过重载webviewclient做更多的事情,如自定义网页出错界面等等。

获取页面标题

我们通常可以通过实现WebChromeClient中的接口去获取与显示网页标题:

mWebView.setWebChromeClient(new WebChromeClient() {
            public void onReceivedTitle(WebView view, String title){
                mTitle.setText(title);
            }
        });

但是当你在一个webview中有不同链接跳转,再通过webview.goback()返回的时候,标题并不会更新,其实我们可以在WebviewClient中实现onPageFinish接口时通过view.getTitle去获取标题,此时goback时也是能获取到标题更新的。

UserAgent

网页的移动端通常有自己的导航栏设计,我们在native中增加了导航栏,如果此时继续让网页的导航栏加载出来,界面就会出现两个导航栏,所以我们需要告诉网页,访问并非来源于一个真正的浏览器,而是一个App,当网页识别到该访问时,即将自己的导航栏隐藏掉。我们可以通过下面这段代码获取并定制专属App的UserAgent.

        WebSettings webSettings = mWebView.getSettings();
        String userAgent = webSettings.getUserAgentString();
        userAgent = userAgent.concat(" app和网页约定的字串");
        webSettings.setUserAgentString(userAgent);

缓存

大多数需要访问网页的App,假设你已经成功访问了网页,那么下一次你断掉网络之后再访问,还是可以看到上次访问的页面,所以我们可以在有网络时去获取新数据,而没有网络时即从webview的缓存中去加载数据。webview有四种缓存模式,根据需要灵活使用。

if (AppUtil.isNetworkConnected(getActivity())) {
            webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
        } else {
            webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
        }

js交互

有时候我们需要在客户端与js代码做交互,在我的项目中,加载网页时,执行一段Js代码,返回用户是否登录的信息,在这里就简单的使用js让客户端弹toast作演示。
首先,定义一个类,用于让js代码调用:

public class WebAppInterface {
    Context mContext;

    /** Instantiate the interface and set the context */
    WebAppInterface(Context c) {
        mContext = c;
    }

    /** Show a toast from the web page */
    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}

调用下面这段代码,将WebAppInterface与webview绑定起来:

WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");

至此,js代码就可以和客户端通信了。

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />

<script type="text/javascript">
    function showAndroidToast(toast) {
        Android.showToast(toast);
    }
</script>

上面这段代码,是写在网页端的,如果我们想客户端主动插入js代码也是可以的,非常简单:

String js = "Android.showToast(\"Hello Android\")"
webview.loadurl(“javascript:”+js);

代码混淆

兴高采烈的打开混淆准备发布应用的时候发现,所有的js调用不生效了!打开proguard-rules.pro可以发现显著的提示:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

所以,我们必须将有webviwe和js交互的类作声明,且必须使用完整的包名路径:

-keepclassmembers class com.google.test.TestActivity {
   public *;
}

同时4.2以上版本中我们需要对js调用接口作@javascriptinterface,声明,为了声明不丢失,我们还需要加上:

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

推荐阅读更多精彩内容