欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

APP打包的那点事

程序员文章站 2022-05-07 08:18:01
...

最近团队有需求将一个移动端网站打包成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*

转载于:https://www.jianshu.com/p/0d21de25ebb0