本文为【Marno】原创,转载必须保留出处!
欢迎关注公众号【aMarno】,主要分享 React Native 技术。
本文属于 Marno 的《Android 快速实现》系列文章,更多【快速实现】文章 点此查看
一、前言
本文旨在提供一个解决思路,不仅适用于添加地图这一种场景。还有更多的场景可以用到,比如展示在线 PDF 文档等。
最近都在忙着讨论项目需求,忙着学习 React Native ,时间一久都快忘记我是一个搞 Andorid 开发的了。今天突然想到了自己在上个项目期间的一个经历。觉得可能会对一些人有帮助,于是就写出来和大家分享一下!
上个项目是一个 O2O 类型的项目,在更新了几个版本之后,老板打算进行推广,进行地铁广告,电梯广告,地推等等。让我把 Apk 大小优化一下,说现在的10M太大了。
二、穷途末路
其实我在写代码的时候已经很克制了。除了一些必备的三方库以外,基本也没有引入什么其他多余的东西。而且我已经做了以下优化工作:
优化图片大小
1.使用 tinyPNG 压缩图片大小
2.有些图片换成 webP 格式,如背景图
3.icon 图标仅保留一套,使用时将 ImageView 大小限制死。仅保留极个别不同分辨率的图标。
4.部分icon 使用 svg 代替,少量优化布局
1.优化层级,减少布局嵌套
2.一个界面一个界面的消除过渡绘制
3.多使用 include 标签,重用布局
4.不必要的布局使用 ViewStub 延迟加载(用的很少)
5.将可复用资源抽取到对应的 res 文件中,如字符串,样式等优化代码
1.实体类去除没用到属性,并将属性设为 public ,去除 get / set 方法
2.减少内部嵌套的实体类,尤其像 GsonFormat 这样的工具生成的实体类
3.能服用的尽量复用。
4.还剔除了一部分我自己常用的打包好的工具类中一些没调到的方法。
5.不过,仅是减少几行代码,对 Apk 体积的优化成效甚微。优化三方库的使用
1.Glide 还是 Picaso 纠结了好一阵子。Picaso 要小很多
2.推送,统计,三方登录,微信支付,地图,这个没法删。但是优化了一下 so 适配CPU的数量。
经过了这些工作后(可能有遗漏,时间太久记不太清了),老板还让我优化 Apk 大小,我就实在是想不到其他办法了。而且我把网上能搜到的关于 Apk 优化的文章基本都看了,只要是能用的都会去试一下。但除了图片以外的优化都收效甚微。
三、灵光一闪
我把 Apk 传到 https://nimbledroid.com 上进行了分析,发现其中最占体积的就是【百度地图】了,足足占了 6M 多。但是我们作为 O2O 产品怎么可能没有地图呢?这是产品经理也不会同意的啊。于是我苦思冥想,采取了曲线救国的方式,干掉了百度地图,最终将那个版本的推广 Apk 包减小至仅有 3.34M。(由于已经离职,下图就不显示App名称了,除非有广告费,哈哈哈~)
思路很简单,就是用 JS 的地图替换了原生的地图。因为我分析了一下地图在这个 App 的功能占比,其实算是一个比较弱的功能,用户要想看到地图页面,必须经历以下的流程。
如上图所示,这个页面的层级比较深,而且根据前面几个版本的页面统计数据来看,确实很少有用户点到这个界面来。但是又不能没有这个功能,所以最终采取了这样折中的办法。性能怎么样呢?再来个图给大家看下吧。
我觉得性能还是可以接受的,虽然不如原生加载的快,但是我很满意了,因为我把安装包缩小了(用到的导航功能是跳转外部地图)终于可以交差了,而且产品经理和老板都没有看出和之前地图的差别来,只是觉得这个小伙子还挺屌的,真的给搞到只剩下3M了(嘿嘿~)。
四、代码实现
相比集成原生地图,集成 JS 地图简直就是不能再更简单了!! 不用下载烦人的 jar 包,不用考虑 so 文件的兼容。而且我觉得 JS 地图只有性能上不如原生,在功能上貌似还要更丰富一点。当然这里只是用于简单的地图展示和添加一个 Marker,更多功能可以自行探索。
但是最开始集成的时候我还是遇到了坑,刚开始使用的是百度的 JS 地图,但是发现在通过 Native 代码调用 JS 代码设置 Marker 的时候,百度总设置失败。网上查了很久,总觉得步骤方法都没有错,但是就是不行,正当我打算放弃这个念头的时候,想起来不是还有高德地图的么,于是试了一下果然就行了。
先大概说一下步骤:
1. 到开发者平台申请 JS 地图的秘钥
2. 在 assets 目录下创建一个离线的 html 页面
3. 在 WebView 中加载该离线页面
4. 通过 Native 调用 JS 方法,在地图上添加 Marker 图标
第一步就不用我说了吧,直接从第二步开始吧。【2】在 assets 目录下创建一个离线地图 html 网页【amap.html】,代码如下↓↓↓,注意看注释!!这里可能需要我们会一点 HTML 和 JS 的知识。速成就好了,只要明白一个 html 页面是如何搭建起来的就行。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<title>基本地图展示</title>
<link rel="stylesheet" href="http://cache.amap.com/lbs/static/main1119.css"/>
<style type="text/css">
html,body{
width:100%;
height:100%;
}
#container{height:600px;}
</style>
<!--<script src="http://cache.amap.com/lbs/static/es5.min.js"></script>-->
<script src="http://webapi.amap.com/maps?v=1.3&key=这里填写你申请的 key"></script>
<!--<script type="text/javascript" src="http://cache.amap.com/lbs/static/addToolbar.js"></script>-->
</head>
<body>
<div id="container"></div>
<script>
var map = new AMap.Map('container', {
resizeEnable: true,
zoom:14,
center: [104.065794,30.657483]
});
//提供JS方法,让webview调用,添加marker
function addMarker(lng,lat) {
map.setZoomAndCenter(14, [lng, lat]);
marker = new AMap.Marker({
//指定 Marker 的样式
icon: "http://webapi.amap.com/theme/v1.3/markers/n/mark_b.png",
position: [lng, lat]
});
marker.setMap(map);
}
</script>
</body>
</html>
【3】然后创建一个带 WebView 控件的 Activity 页面,在代码中将该 WebView 的 setJavaScriptEnabled() 方法设置为 true,然后通过 webview 加载 asstes 中编写好的离线地图 amap.html 文件。
mWebView.loadUrl("file:///android_asset/amap.html");
【4】最后在 JS 地图上设置 Marker 就行。这里涉及到了 Native 调用 JS 代码,不熟悉的可以搜索一下。
mWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
//调用JS方法,将商家坐标设置到地图上
mWebView.loadUrl("javascript:addMarker(" + shopLng + "," + shopLat + ")");
}
});
五、结语
这个 App 是一年多以前写的了,因为最近在学习 React Native,就突然回想起了那次通过 JS 解决问题的经历。 所以写出来和大家分享一下。其实还有很多业务可以通过这种思路去解决,但是通过 WebView 调用 JS 代码毕竟还是存在性能上的局限性,所以才会出现像 RN 这样的技术。恩…看来还是要早点把 RN 学好才行!哈哈~
看完点个关注呗!我有个 RN 群就缺你这样的人才。早点来吧~
公众号回复 RN ,就送你入群“邀请码”。你想啥呢?我这是正经邀请码哈!