中文移动开发所想—火山平台为例

此文写于偶然间发现火山安卓平台发布了 libGDX 类库的即兴思考,组织较为混乱,也可能包含技术或事实错误,还请指正。 部分观点较为主观,无引战意思,还望海涵,请勿撕逼。 引言 说起中文编程,易语言绝对是领导者。尽管其有着数不清的槽点,也因此被专业人士嘲讽,但事实胜于雄辩——易语言至今还拥有相对活跃的社区,众多非科班的业余开发者照样使用易语言做出了优秀的软件,也在不少接单平台拿到了足以维系生活甚至不菲的收入。易语言也算是我入开发坑的引路人,最初小学四年级时接触过 VB,本来英语就很差的我差点昏厥 🤪。别看区区几个关键字,光是 int, float, bool 之流就已经很头疼了。后来五年级试用易语言像是打开了新世界的大门,一直持续到初三才转的 JAVA。 转 JAVA 的契机就是 PC 流量逐步迁移至移动设备,再加上中学生使用电脑本来就不多,上课玩手机到是不少 😜。在迁移的过程中,一匹黑马打乱的这一进程——E4A。这是一个第三方仿照易语言开发的面向 Android 的中文开发工具,最初是基于已经停止维护的 Google Simple 语言开发而来。开发 Android 应用是许多易语言用户的心愿,当然也包括我在内。幸好当时的 E4A 还是萌芽时期,各种支持库非常不完善,甚至达不到「可用」的标准,否则或许我就错失了转向正规军的最后机会。(此处正规军指的是对应平台官方支持的原生开发,无歧视含义) 现在是2020年了,吴涛先生憋了多年的大招虽然姗姗来迟,但也在稳步发展——火山软件开发平台。显然这与 E4A 不是一个量级的产品,也体现了吴涛先生宏大的理想:做一款中间语言,能够编译到各个平台从而实现真正的大一统。这个想法并不罕见,但打出中文的口号倒是首家,吴涛先生将其称为语言之上的语言。尽管早已转向更大众的技术栈,但仍情不自禁地关注中文开发的动向,近期在研究 libGDX 相关东西无意中又搜到了火山安卓开发平台的相关内容,或许这就叫羁绊吧。 偶遇&现状 libGDX 是一款采用 JAVA 的跨平台游戏框架,近年来由于国内环境问题,个人独立游戏渐渐没落,而大型游戏通常需要更专业的游戏引擎,因此 libGDX 国内资料奇缺。而在搜索引擎给出的结果中,几个近期发布的页面格外醒目:LibGDX引擎里面有没有封装box2d库? - 火山安卓俱乐部 - 火山软件…。没想到火山官方团队也瞄准了这一开源框架,在 Volcano3D 游戏引擎较为专业、入门困难的背景下,或许引入这一小巧的框架能大幅提升火山安卓开发平台在游戏方面的表现。 老友邂逅定当叙叙旧,我花了近2天时间大致了解了下 E4A 与火山安卓的现状,也重点关注了 libGDX 支持库发布后的市场反应。结论有点遗憾,目前看来整体不尽如人意。 火山安卓官方论坛日均帖子数在50左右,其中还包括很多官方的模板式回复,与易语言难以相提并论,相当于小众中的小众。 火山安卓曾也有引以为傲的作品— Pandownload 安卓版,随着不久前 PC 版开发者被逮捕,安卓版相关帖子也被迅速撤掉,尴尬的是,在此之前,火山甚至使用官方账号对 Pandownload 大肆赞扬,并赠送其一套正版火山密钥以资鼓励(原帖已被删除,当时截图不完整没有体现发帖账号)。除此之外,官方账号还为一个疑似炒共享经济概念的产品做推广,原帖备份在此。当然,作为平台的开发方对自家平台开发出的著名软件鼓励推广是无可厚非的,但类似 Pandownload 之类处于灰色地段的程序,竟然毫不避讳地用官方账户表扬着实值得商榷。这也侧面表明火山开发平台遇到了和易语言类似的情况,即用户多是非专业人士,所开发的产品往往也是非专业产品。常规的小工具基本上没有发展空间,唯独灰色产品(例如采集、破解、外挂)或者打一枪换一炮类产品有增长的可能。毫无疑问这种生态对平台的发展是非常不利的,火山官方不清楚是真的不知道,还是没有办法,竟然将这一不利因素视为救命稻草,妄想借此来壮大生态,其后果难以想象。 libGDX 类库或许因为发布较晚,目前社区还没有太多的讨论,同样没有成功案例出现。论坛里仅有的帖子则全部是封装 bug 的反馈。这不禁让我想起 Cocos2d-js 引擎的困难处境。Cocos2d 一开始是 IOS 端游戏引擎,后来发展为跨平台,进而引入了 Lua 脚本后期又引入了 js 脚本,并实现 js 绑定。Cocos2d 曾希望将开发的重点转移到 js 来实现对 html5 的支持,对于 Native 设备则是将 js 绑定到原生 API。不巧,原生 API 经过多轮改变已经非常混乱,于是又引入了绑定生成框架在自动化这一繁琐的任务。折腾了许久,Cocos2dX 原生引擎,以及衍生引擎基本上都停滞了,重点转向了 Cocos Creator 这一对标 Unity3d 的全新平台。我最后接触 Cocos2d-js 是在2018年,那时 js 绑定非常不完善,众多 API 在 web 端与本地端行为不一致,甚至函数参数都不一致,对于一个一跨平台为卖点的产品,这是致命的打击。...

May 11, 2020 · Chenhe

Android 磁盘最近最少缓存实现 - DiskLruCache 源码分析

 DiskLruCache 是一个 Android 端使用广泛的磁盘 LRU (最近最少使用)缓存算法的实现库,甚至在 AOSP 中都有使用。 基础使用 为了对整体架构有个印象,方便找分析入口,先看看基本的使用。 实例化: val cache = DiskLruCache.open(cacheFile, version, valueCount, maxSize) 写入: val editor = cache.edit(key.md5()) val os = editor.newOutputStream(0) 读取: val snapshot = cache.get(key.md5()) val is = snapshot?.getInputStream(0) 关于它的具体使用可以看这篇文章。 整体来看并不复杂,实际上代码量也确实不多。通过读取时的 snapshot 封装猜测后续修改不会影响已经读取到的值。 日志文件 DiskLruCache 的一个显著特征就是在缓存目录有一个 journal 文件,用于记录所有操作日志,大概长这个样子: libcore.io.DiskLruCache 1 19 1 DIRTY c915a1313f3e413252fae2957469dcd2 CLEAN c915a1313f3e413252fae2957469dcd2 50196 READ c915a1313f3e413252fae2957469dcd2 DIRTY 8b33d00d5f9d443095e20829a1367e05 CLEAN 8b33d00d5f9d443095e20829a1367e05 159594 前五行是元数据: 一个魔法数,固定字符串,用于标识这是一个 DiskLruCache 的日志文件。 DiskLruCache 版本号,从发布以来就没变过,预留一下便于后续格式更新。 开发者声明的应用版本号。 每个 key 对应几个 value,一般都是1。一个 key 支持写入多个值,每个值都是一个文件,文件名是 key....

March 9, 2020 · Chenhe

Git HTTP+SSH 代理配置

本来是没有什么技术含量的东西。奇怪的是网上答案千篇一律而且大部分都是错的,不知道要坑坏多少人:smiling_imp:。 HTTP 代理 HTTP 代理相对简单 # HTTP 代理 git config --global http.proxy http://127.0.0.1:1080 git config --global https.proxy http://127.0.0.1:1080 # Socks5 代理 git config --global http.proxy socks5://127.0.0.1:1080 git config --global https.proxy socks5://127.0.0.1:1080 注意这里的 socks5 仅仅是代理使用的协议,它依然是针对 http 设置的,所以仅对 http 协议的仓库有效。使用 git@xxx 这种 ssh 连接的不会使用代理。 也可以分域名设置代理: git config --global http.https://github.com.proxy http://127.0.0.1:1080 git config --global https.https://github.com.proxy https://127.0.0.1:1080 SSH 代理 SSH 代理需要在密钥目录 (~/.ssh) (Windows 下是 C:\Users\{UserName}\.ssh) 新建一个 config 文件,没有后缀名。 Linux 系统写入以下配置(未验证): # 需要 netcat ProxyCommand nc -v -x 127....

March 3, 2020 · Chenhe

Android 自定义 View 的默认属性值(四个构造函数的作用)

常见的套路 自定义 View 同学们一定或多或少都接触过,毕竟设计给出的样式往往从来不是系统默认的🙂。 自定义 View 时往往遵守下面这样的套路: 在 attrs.xml 中声明自定义属性(或使用系统预定义属性),经常用 declare-styleable 包裹起来。 继承一个 View 并写两个构造函数:constructor(context: Context), constructor(context: Context, attrs: AttributeSet?). 前者用于代码创建,后者用于 xml 创建。 context.theme.obtainStyledAttributes() 来读取属性值,并在 getXXX() 函数中给出一个默认值。 一切似乎理所应当行云流水并且工作良好,但这真的合理吗?(废话 要是合理这篇文章是在自嗨嘛😅 考虑以下问题: 用户(本文指使用 View 的开发者)如何统一设置默认样式? 默认值硬编码在代码文件中是否耦合过重? 当然用户可以定义一个 style 每次使用都设置一下,你不觉得太麻烦了吗? 当然也可以直接写在主题的样式中,但如果有冲突属性怎么办?例如自定义 View 使用了系统定义的 android:textColor 但又不希望其他控件例如 TextView 受影响。 为了后边便于说明,我们定义个 CircleCheckBox,并定义如下属性: <!--lib: attrs.xml--> <resources> <declare-styleable name="CircleCheckBox"> <attr name="normalColor" format="color" /> <attr name="selectColor" format="color" /> <attr name="outlineColor" format="color" /> <attr name="outlineStrokeWidth" format="dimension" /> <attr name="android:checked" /> </declare-styleable> </resources> 被忽略的两兄弟 除了常用的两个构造函数之外,还有一个三个参数的构造函数,从 Android 5....

February 16, 2020 · Chenhe

一起动才够嗨!Android CoordinatorLayout 自定义 Behavior

CoordinatorLayout 的今生前世 联动效果 现代化的 Android 开发一定对 CoordinatorLayout 不陌生,CoordinatorLayout + AppBarLayout + CollapsingToolbarLayout + Toolbar 的全家桶更是信手拈来,无需一行代码光靠 xml 就能实现下面这种折叠导航栏的炫酷效果: 这种搭配的教程已经非常多了,不是本文的重点。在使用 xml 时候肯定不少同学掉过一个坑:界面主要内容与头部元素重叠了!粗略了解一下因为 CoordinatorLayout 的布局方式类似 FrameLayout 默认情况下所有元素都会叠加在一起,解决方案也非常玄学,就是给内容元素添加一个 app:layout_behavior="@string/appbar_scrolling_view_behavior" 属性就好了,简直像黑魔法! Unfortunately,代码并没有魔法,我们能偷懒是因为有人封装好了。跟踪进这个字符串是 com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior 显然这是个类!事实上这就是今天的重头戏 —— Behavior. 这个效果太复杂了,所以 Google 才会帮我们包装好,下面换一个简单的例子便于学习: 这是仿三星 One UI 的界面。上面是一个头布局,下面是一个 RecyclerView,向上滑动时首先头布局收缩渐隐并有个视差效果,头部彻底隐藏后 RecyclerView 无缝衔接。向下滑动时同理。 事件拦截实现 在继续探索之前,先思考一下如果没有 CoordinatorLayout 这种现代化东西怎么办?因为这牵扯到滑动手势与 View 效果的糅合,毫无疑问应该从触摸事件上入手。简单起见暂时只考虑手指向上滑动(列表向下展示更多内容),大概需要进行以下操作: 在父布局 onInterceptTouchEvent 中拦截事件。 父布局 onTouchEvent 处理事件,对 HeaderView 进行操作(移动、改变透明度等)。 HeaderView 完全折叠后父布局不再拦截事件,RecyclerView 正常处理滑动。 现在已经遇到问题了。因为一开始父布局拦截了事件,因此根据 Android 事件分发机制,哪怕后续不再拦截其子控件也无法收到事件,除非重新触摸,这就造成了两者的滑动不能无缝衔接。 接着还有一个问题,反过来当 RecyclerView 向下滑动至顶部时,如何通知 HeaderView 展开? 哪怕解决了上述主要问题,肯定还有其他小毛病,例如子控件无法触发点击事件等等等非常恼人💢。假设你是大佬完美解决了所有问题,肯定耦合特别严重,又是自定义 View 又是互相引用的乱七八糟😵 所以现在就不往下深究了,有闲情雅致有能力的同学可以尝试实现。...

February 15, 2020 · Chenhe

Android 事件分发机制

Android 事件分发机制一直让人头痛,之前也是面向 GitHub 编程得过且过。今天下定决心了解一下,以便后面自己定制 View 效果。Android 触摸事件有三个基本类型:ACTION_DOWN, ACTION_MOVE, ACTION_UP,后两者的传递顺序取决于 DOWN 的传递结果,所以就从 ACTION_DOWN 开始分析。 ACTION_DOWN 全景 借用一张下面参考文章里的全景图片,注意这里指的仅仅是 ACTION_DOWN 事件的传递。先解释一下: 白色箭头表示事件传递(函数调用) 箭头上的标注表示调用前提。(supper 表示上一级直接调用,false 表示若上级返回 false 则系统继续向下调用) 白色方块内的消费箭头表示若此函数返回对应值,则事件终止传递(也称作被消费了) 以左上角事件入口为例,首先 Activity 收到事件触发 dispatchTouchEvent,不论返回 true 还是 false 事件均终止,任何组件的任何函数均不会再被调用(包括 activity 自己的 onTouchEvent),只有 return super.dispatchTouchEvent() 也就是调用了 super 才会继续传递到下一级。 对于下一级 ViewGroup 的 dispatchTouchEvent 来讲,返回 true 同样消费事件立即终止传递。返回 false 则会回溯到上一层的 onTouchEvent。调用 super 则继续向下传递。 全程传递 我们假设事件没有被拦截、消费,那么整个传输流程类似 U 型: 不难看出,整个流程分为左右两部分,我们暂且叫做分派与回溯。分派是自顶到底的,主要用于事件的传递。回溯是从底到顶的,主要用于事件的处理。所有方法的默认实现就是 return super.xxx() 因此事件默认情况下可以走完整个流程。 拦截器 ViewGroup 细心的同学应该注意到了,在分派过程中除了整齐的 dispatchTouchEvent 方法外,乱入了一个 onInterceptEvent 方法,可以称之为拦截器。顾名思义拦截器的作用就是拦截此事件供自己使用(就像大理 gov 一样对待口罩那样)。不难看出 dispatchTouchEvent 方法调用后根据内部处理的不同有三个后果,分别是 ①终止传递 ②向下传递 ③向上回溯,而前面提到过,一般来讲处理具体的处理会放在 onTouchEvent 中。那么问题来了,终止传递后我居然自己无法处理事件?(参考 U 型图中的 ViewGroup 层,无论 dispatchTouchEvent 作何响应都无法调用自己的 onTouchEvent)...

February 13, 2020 · Chenhe

Jenkins+Github 持续测试

说明下环境: Windows 10 (因为还需要跑其他一些东西) Jenkins 2.204.1 LTS 内置 Jenkins war 2.217 配置 GitHub 鉴权 Jenkins 的安装过程很简单就不写了。首先需要安装 GitHub Plugin 插件,如果安装 Jenkins 时选择了安装常用插件那么应该已经装好了,否则就去手动安装一下。 为了和 GitHub 账户连接,当然要配置一下鉴权。进入 Manage Jenkins - Configure System,找到 GitHub,添加一个 GitHub 服务器,API URL 保持默认 https://api.github.com 就行,名称随便填。点击凭据右边的问号可以看到帮助。 去 GitHub 生成一下 AccessToken,Note 就是一个备注随便填,下面的授权范围要勾选 repo 和 admin:repo_hook. 复制一下生成的 Token 回到 Jenkins 添加凭据,类型选 Secret text,将 Token 粘贴到 Secret 编辑框内,ID 留空,描述 自己填一下其他保持默认。 最后在下拉框中选选中刚刚添加的,点一下连接测试,通过就行啦😁 Webhooks Webhooks 用于当发生特定的事件(例如一个新的 push)时 GitHub 主动去通知外部服务。打开需要集成的项目,进入 Settings - Webhooks,点击 Add webhook....

January 28, 2020 · Chenhe

Moshi with Kotlin Json 库—现代化的最佳损友

Moshi 与 Kotlin Android(Java) 平台已经有许多 Json 库了,包括 Google 推荐的 Gson,广受欢迎的 Jackson,阿里的 FastJson 等,但今天要说的是大名鼎鼎 Square 公司的 Moshi. (什么?没听说过 Square?OkHttp, Retrofit 可都是他的著作) 轮子已经有很多了,不过自从 Google 将 Kotlin 定为 Android 亲儿子开发语言后,竟然包括 Gson 在内的几乎所有 Json 库均不支持,这当然可以理解,因为他们大多数采用了 Java 反射机制,注定难以适配 Kotlin 独有的特性。因此今天要介绍 Moshi —— 一个与 Kotlin 兼容极好的现代化解析库。 传统 Java Json 库用于 Kotlin 主要产生两个问题: 不支持空安全。即使 Kotlin 变量定义为非空,若 Json 为空则解析出 null 而不会抛出异常,直到数据使用时才抛出诡异的 NPE. 为啥说诡异?因为定义非空的变量默认不需要进行空判断,但实际上他是空的,有点挂羊头买狗肉的意思。 不支持默认参数。Kotlin 的 data class 极大地方便了开发,默认参数的语法更是直呼太爽。可惜这种现代化写法或遇到两个问题:①默认参数无效。②解析失败因为没有无参构造函数。而解决办法更是令人崩溃:①不要使用默认参数。②给所有形参全部加上默认参数。 因此,如果你已经使用 Kotlin 作为主要语言,Moshi 将会是绝佳的选择。(KT 自带的解析库也可以考虑) 另外 Moshi 的贡献者也是 Gson 的主要贡献者,因为 Gson 的先天不足且他已经离开了 Google,故开发了 Moshi,具体可以参考他在 Reddit 的回答:Why use Moshi over Gson?...

January 25, 2020 · Chenhe

凛冬的成都白色的九寨

宗旨声明与安全提醒 所提所有商家为亲自尝试后的推荐,无其他利益关系,你应当始终根据自身偏好自主选择适合的消费。 全程有意地规避了网红景点与多数历史文化景点。 冬天景区效果受天气影响较大。 非穷游攻略。(大部分钱花在了交通上,三飞一高铁) ⚠️🚁无人机安全提醒 在气温较低且空气湿度较大(有雾)的地区请勿使用无人机。如果坚持使用必须先升空观察至少1分钟。因为此环境下螺旋桨会结冰严重影响气动性能,并且短时间内无明显异常,App 无安全警告且飞机姿态正常。一旦发生结冰在数秒内飞机会快速下降且不受控,多数飞手不能及时反应过来。 若在悬停时 App 提示已达最大动力,或输出电流异常,必须立即降落,此时已经开始结冰。 需要使用暖宝宝或其他方式对电池进行预热。尽管这样,App 返航预估电量依然不准,在第一次警告(黄色)时就必须立即返航。 如果你正巧想换一架新的无人机,请忽略以上提醒🙂 重庆市区 如果你做了一些攻略,那么对下面名字应该非常熟悉:宽窄巷子,锦里,IFS,春熙路,太古里,杜甫草堂,武侯祠,XXX小吃集。很抱歉,这些地方我们都没去,或者说没有作为一个景点专门安排时间去。那么有人就要问了,那还有什么地方能去呢?答:没有😂 事实上,我们选择了几个距离住宿比较近的地方作为饭后散步或者填充碎片时间之用。很多反对者把宽窄巷子形容为小吃街,这点我是不敢苟同的。它其实不像济南芙蓉街北京南锣鼓巷那样充斥这路边小摊,将其比作为迷你版的丽江古城可能更加贴切。宽窄巷子很小,比上述的两个类比都要小,如果你喜欢这种喧嚷的文艺气息,倒也不妨找个咖啡店之类的坐坐(有家星巴克🙃),否则的话,像我们这样的,用不了半小时就逛完了,甚至懒得拍照。 锦里没有去,估计和宽窄巷子差不多吧。IFS 就在春熙路上,春熙路之所以有名是因为自从很久之前就一直是成都的商业中心,发展至今,它和你家的苏宁广场、万达广场、大悦城没有什么实质性区别。非要说特点的话,也许趴在楼顶的一个大熊猫🐼算是独特之处。 杜甫草堂,武侯祠顾名思义算是当地著名的历史景点了,不太感兴趣也就没去。城市之中的一片绿大概也就类似家乡的公园一般,如果对相关人物没有足够的了解怕是看不出什么名堂。 饮食🥣 来到四川这绝对是一个重头戏,所谓的苍蝇馆子别说是外地人,就算是老成都也不见得能一清二楚。所以妄想在网上随便搜搜就找到一个地道的小吃还是放弃吧,大概率找到的是被精心包装过的网红餐馆。 这里顺便说一下对小吃街的看法。越来越多的自由行同学已经对小吃街有了抵触心理,我当然也不例外甚至更加极端。不可否认,全国各地的小吃街正趋于严重的同质化,什么湖南臭豆腐,xxx老酸奶,铁板系列,炸串系列……闭着眼都历历在目。尽管吐槽声不绝于耳,小吃街依然人头攒动。“存在即合理”,但合的只是一部分人的理。旅行说白了就是从自己活腻的地方到其他人活腻的地方去看看,有人希望品尝到真正特色的餐饮,也有人希望感受到喧闹熙攘的氛围。因此没必要把小吃街一棍子打死。我们在这里居高临下地批判着又贵又难吃,说不定有人正是享受这样消费的过程呢。当然我在规划时就已经拉黑的全部小吃街❌ 四川的火锅🍲一直闻名全国,但事实上重庆的火锅要比成都更加普遍和特色。鉴于我已经去过了重庆,因此这次没有关照这一美食。通过网上粗略的搜索,大龙燚和小龙坎似乎是成都当地的,但是emm,这两家不是全国都有么🤪 曾经去过成都的朋友给我推荐了「重庆当年老火锅(成都旗舰店)」,位于成都东站东部,但是名字都叫重庆火锅了哈哈哈哈。 相比火锅,成都的串串🥓可一枝独秀了。这里推荐的店铺是「叶婆婆钵(bō)钵鸡」,来自一个成都本地的朋友,他自己就经常吃这家。这是一个连锁店,并不是小吃或苍蝇馆子,但完全不用担心消费问题,我们两个人只吃了54块钱,一盘用料很足的蛋炒饭也不过10块钱,哪怕全部串串吃到饱估计也比火锅便宜一半左右。味道也是非常的可以,有红油和藤椒可选。红油相对缓和一些,藤椒是四川非常有特色的麻+辣,有能力的建议藤椒。 除了串串还有一些当地的菜品,此类推荐的是「陈麻婆豆腐」(好像他们比较喜欢用婆婆起名字😆),我们选择的是旗舰店(青华路店),同样是一个连锁店,并且装修相比叶婆婆更加别致,不过依然不用担心消费,两人吃了92块钱。一盘麻婆豆腐¥22,毛血旺¥62,毛血旺超大一盆而且没有套路,两道菜我们俩都没吃完,买单的时候建议他们涨价哈哈哈哈🤣 还有两家是之前筛选出来的但因为种种原因没去,小伙伴们也可以去试一下,分别是重庆森林(火锅,川大附近),冒椒火辣串串火锅(魁星楼,近宽窄)。 此外当地朋友推荐的小吃还有肥肠粉,冒节子,甜水面,这些就不分店家了,路边找个小摊就可以,但不要去小吃街。最后逛街过程中发现他们很喜欢吃兔子,尤其是兔头,就像周黑鸭那样普遍,如果对此没有忌口还是值得尝试一下,按个卖的。下面这家双流老妈兔头兔头还可以,其他的一般,这家的豆花就是豆腐而且有点腻,与重庆的不同,喜欢吃甜的可以尝试否则不推荐。 都江堰 来到成都第一站的是都江堰,成都到都江堰有城际动车很方便,没有必要去做旅游大巴。出了火车站距离都江堰景区也很近,没有必要做火车站外拉客的车。都江堰外围应该加强管理,见到好几个拉客的起着摩托车追着自驾的汽车问,非常危险😒。 都江堰景区很大,需要耗费半天的时间,游览线路如下图所示,我们早晨从成都过来,大概12点才出都江堰。检票口进来后一直直行基本上就是沿着堰走,冬天属于枯水期,基本上所有水都被引导灌溉渠里,好处就是可以清楚地看出这一世纪工程是怎么实现自动分流的。(其实很简单啦,就是外侧河道高一些,这样水多的时候就会从外侧流走不至于把灌溉渠淹了) 走到头后通过吊桥来到对面,这里主要是道观山路和商业,要比来的时候的平路累不少,不过因此也有了制高点的观景台(上图拍摄地),实在不想爬山回去的话,可以从吊桥走回去买个观光车票原路返回。 会有不少人把下午安排给青城山,毕竟来都来了。然鹅我实在太累了😑,大概2点回到成都去吃上文提到的叶婆婆钵钵鸡。后边巴士上遇到两个小姐姐在全程吐槽青城山又累又无聊,只有树连水都没有哈哈,仅供参考。 还有小半天+一晚上,小伙伴们可以在上面提到的历史和网红景点中任选来打发时间。我们去了成都博物馆,和春熙路 IFS 很近可以一起逛完。 西岭雪山 西岭雪山与峨眉山+乐山是两条线可以任选其一。我们住在🏠如家精选宽窄巷子西蜀汉路东地铁站店,距离茶店子客运站很近,其有发往西岭景区的直达大巴,在四川汽车客运网订票。需要注意的是正规途径只有去程没有返程,返程是同一辆车不过是私人收费,比去程贵了10块,无法预订,在去的途中司机会给你发名片,上面标注了返程时间和联系电话。不同时期返程时间也会浮动,建议具体咨询。返程虽然看起来不太正规,不过也是直达茶店子,没有绕路或购物等情况。 鸳鸯池与日月坪 西岭分为两段,第一段是鸳鸯池,所有的娱乐项目与商业都集中在此,也是必买索道的一段(冬天登山道封闭),只想玩项目的同学到此就行了。第二段是到日月坪,景色非常不错,外地来旅游的同学们强烈建议上去。 鸳鸯池位于半山,绝大部分时间是雾气笼罩,即使我们看起来“雾气很大”在当地已经算是晴朗了,因此看不到什么风景。雾气集中在早晨9到12点以及傍晚,想玩项目的同学尽量错开,否则能见度一下来大多数项目都要关闭。下图的鸳鸯池算是较为晴朗: 同学们大可不必担心到了山顶日月坪啥都看不到,日月坪索道海拔上升1000多米,会直接穿到云上,头顶阳光灿烂,脚下云海茫茫,这是在九寨沟也看不到的情景。整个山顶日月坪到阴阳界还有往返 2.6km 的山路要走,下山索道下午5:30关闭,保安大概在4点多就开始从阴阳界赶人了。大巴车1点才到的山脚下,到达日月坪已经两点半,所以游览时间比较紧张。到阴阳界的最后300米是落差极大的楼梯,很可惜时间紧迫加上体力不足我们最终没能到达。 山顶日月坪有个首峰别苑住宿,一共只有10间客房,可不必赶索道下到鸳鸯池,价格嘛…🤑 日月坪雾气变化很快,一时被挡住不要心急,5分钟内一般就能看见。有三脚架的可以拍延时哦~ 这里看起来非常适合飞无人机🚁,那么请回到最顶上看看安全提示。别问我怎么知道的,如果坠机了回到大疆主页点击菜单,有个找飞机选项,点击飞机可以开启蜂鸣器和机臂灯。 时间安排与消费 如果想玩项目妥妥地按照两天安排,第一天中午到达去山顶或者直接开玩,然后第二天进行另一项。但是我们就比较尴尬,不打算玩项目,但是晚上下山的话可能没有会成都的车。另一个选择是晚上下山找个车去花水湾泡温泉+住一晚,然鹅我们对温泉依然没有兴趣。所以还是在山上呆了一晚这样也不会太赶。山上的住宿被垄断,贵是肯定的,而且因为时间很久了设施比较陈旧,加上气候潮湿可能还有一点味道,也在可接受范围内,并没有网上评价的如此不堪就像猪圈那样。鸳鸯池最便宜的住宿是阳光酒店,评价不堪入目,因此我们选择的是其次的雪花酒店,虽然评价也很差,实际体验下来的话还可以,送早餐。最好的住宿是映雪,在西岭官网都可以看。 想囤积自热锅和方便面的可以省省了。鸳鸯池有家德克士,价格公道营业到夜里11点,别蹭用餐高峰去很舒服。同样有个红旗连锁,红旗是成都很有名的连锁便利店,大街小巷随处可见,东西只比城市贵1-2元。西岭已经覆盖了4G信号,要准备现金的攻略已经过时了。 第二天中午返程,下午3点左右可以回到茶店子。又来了个小半天的碎片时间,可以从上述网红和历史景点中任选去打发。我们选择了离酒店比较近的金沙博物馆,注意这个博物馆是收费的80,特殊群体依法半价。 熊猫基地 到成都就必须得去看看熊猫,熊猫繁育基地作为一个科研机构,旅游是顺便公益性质的,门票很便宜。冬天也是去看的绝佳时机,因为熊猫怕热,夏天的话就只能呆在空调房里的,现在他们都在户外活动。步行游览官方推荐线路分别是1.5和3小时,如果要坐电瓶车别傻傻地在入口等,人巨多,先步行到下一个景点再坐车也无妨。 熊猫基地最好早点去,一来是人多,二来中午会有饲养员喂食可以近距离观察,然后… 他们就要睡觉了💤 你一定不希望看所有家伙都在趴着睡大觉吧。 九寨沟 九寨沟刚刚对散客开放,还有部分景点尚未开放。冬天是九寨沟的超级淡季,阿坝州的旅游做的很规范,到阿坝旅游官网统一购票,各个酒店与餐馆举报电话随处可见。成都去九寨沟冬天遇到下雪的话可能要11小时的车程,或者飞到九寨沟黄龙机场。机场距离黄龙比较近,常规路线是先去黄龙,次日逛完后再去九寨沟。黄龙、机场、九寨沟在一条山路上来回走👻 我们因为时间紧张就直接去了九寨沟。 机场有到九寨沟的大巴50一人,我们是在马蜂窝定了一个接机,他们正在搞活动冲好评100/车经济型,正好遇上暴雪又给升舱成230的舒适型了。店铺叫萤火旅行,到了酒店主动提出第二天免费专车送到九寨沟入口,如果需要的话还可以从出口免费送到酒店,服务很贴心,所以最后买了点他们的牛肉干就当补车型的差价了,有需要的小伙伴可以考虑下这家。 九寨沟旺季和淡季采用不同的方案。旺季的内部公交循环发车,淡季是进入景点就固定一个公交和一个讲解员,每到一个景点下车给一些时间游览。其实感觉还是滚动发车更自由一些,这个是不能选择的。景区整体采取大巴+栈道混合游览方式,步行栈道总里程大约有2km,景点间乘坐公交。想全程步行的省省吧,20多公里可不是闹着玩的。...

January 13, 2020 · Chenhe

Android7 https 抓包

系统限制 Android 7 开始系统有了一个非常安全(讨厌)的限制,所有应用默认情况下不再信任用户自行安装的证书,而仅信任系统预装的。因此,即便我们安装证书后也无法愉快地抓包了:confused: 但是这一限制仅对 targetSdkVersion>=24 的应用生效。 下面提供几种方案绕过这一限制。 添加证书信任 本方案需要修改 AndroidManifest,推荐用于自己的应用,其他应用需要重新打包了。 首先在 res/xml 中创建一个网络安全配置文件,信任用户证书: <?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true"> <trust-anchors> <certificates src="system" /> <certificates src="user" /> <!--信任用户添加的证书--> </trust-anchors> </base-config> </network-security-config> 然后在 Manifest 的 application 节点新增一个 android:networkSecurityConfig 属性指向刚才创建的配置文件即可: <?xml version="1.0" encoding="utf-8"?> <manifest> <application android:networkSecurityConfig="@xml/network_security_config"> </application> </manifest> 使用子系统 此方案本质上是降低系统的版本,例如 平行空间 等双开应用,会创建一个独立的运行环境,相当于子系统。这个环境内的系统版本不一定与手机系统相同。目前,平行空间 4.0.8625 版本以下系统 API < 24,应该可以正常使用。 同理,你也可以使用模拟器抓包,或者干脆找一个旧系统的手机。 修改系统证书 此方案需要 ROOT. 既然默认只信任系统证书,那我们何不直接把自己的证书导入为系统级别? 注意,Android 系统证书使用的是 .0 格式,不同于常见的 .cer/pem,需要使用 openssl 命令行工具转换下。 确定文件名 .cer 格式证书执行:...

November 26, 2019 · Chenhe