普通视图

发现新文章,点击刷新页面。
昨天以前码农明明桑

想去海边-山东半岛自驾游

2024年7月12日 20:34

小朋友放暑假了,工作也不忙,而梅雨季的上海天天都在下雨,就想要来一次说走就走的旅行,奈何一家三口都病了,直到小朋友挂完三天点滴差不多好了,终于启程了。这一次简单的构思了一下目标就是一路往北跑,沿着海岸线玩水。

Day 1 日照万平口海水浴场

提前一天已经把车子送到了服务中心,把座椅通风异响和空调风道弄了一下。早上从上海的家里启程,在服务区吃个午饭充个电,下午到达日照。往海水浴场去的路上吃了此行的第一顿海鲜大餐,团购的2-3人餐,只要150,应该算是这一程最便宜的一顿了,三个人把一锅的蒸汽海鲜加上鲈鱼吃完,鲅鱼水饺和疙瘩汤就只能尝一尝味道了。随后便驾车前往海水浴场,玩到天黑透,小朋友仍然不愿意回去。

Day 2 青岛八大关

由于前一天车子的门把手收不回去了,预约了今天去车子的服务中心检查,一早便出发了,然而由于配件订货需要时间,暂时就不修了。路边找地方吃了个包子,就驾车前往青岛。

在八大关附近停了车,附近吃了个饭,喝了个崂山可乐,便溜达到了附近的海滩。此时正值一天中最晒的时刻,劝阻小朋友许久才终于离开海滩。在八大关景区转了了,公主楼和蝴蝶楼人也挺多,就没买票进去。天气看起来开始下雨,就开车前往预定的住宿处,安顿下来。

晚上吃完饭,开车到达石老人海水浴场,天仍在下着小雨,天也已经黑了,海边已没有几个人了,只有一些在用金属探测器检测海滩的工作人员还几个游客,我们转了一会也就回去休息了。

Day 3 青岛石老人海水浴场,威海荣成那香海

早起吃完饭,本打算前往崂山景区。驾车过程中又经过了石老人浴场,便进入游玩。给小朋友换上泳衣,带上泳圈,带他在海浪中玩耍,玩了许久仍不愿离开,一直玩到接近中午,看来崂山也只能留到下次再来了。要到了中午吃饭的时间,终于把小朋友劝中了,给她冲澡才发现身上已经晒黑了许多,穿衣处和裸露处色差很大。

下午到达那香海,这一片连着好几公里的海边都是沙滩和海水浴场,相当热闹,也有许多游客。然而一路都不需要车辆掉头,开了好久才成功掉头,在海边的停车场停下。当即决定,把车里的天幕搭起来遮阳。小朋友在海边玩水,捡石头,累了到天幕下休息一下。就这样一直玩耍到太阳沉下去,在海边吃完一顿烤串。

可能这是这一趟最开心的一天了。

Day 4 威海鸡鸣岛,威海公园

早上赶往鸡鸣岛码头乘船,买了海鸥爱吃的淀粉肠(不是薯条🤣),乘船前往鸡鸣岛,往来鸡鸣岛的船很多,几乎不用等待就开船了,很多海鸥追逐着我们的船,很多人在甲板喂海鸥。

没多久就到了鸡鸣岛,这个岛不大,花了两个小时就沿着岛转了一圈,据说是因为拍摄《爸爸去哪儿》这个岛才火起来的,岛边很多海鸥等待游客喂养,岛边有一些礁石比较好看,除了灯塔,龙王庙之外,岛上还有几个有特色的咖啡店,岛民经营的民宿餐厅等。岛不大,商业气息也不太严重,还不错。

离开鸡鸣岛,就驾车到威海找了个商场吃饭。吃完饭前往威海公园,沿着海边走走停停,看别人抓鱼,看游人骑行,本想去看那个大相框,走了许久才发现走错方向,赶紧调转方向。终于走到大相框,发现人太多了,根本没法拍照。就又返回车上,搜索了当地的点评必吃榜,去葡萄滩附近吃海鲜了。

点了很多的海鲜烧烤,有一些也是之前从来没吃过的,酒足饭饱之后又走到了葡萄滩海水浴场玩耍一会,结束了一天的行程。

Day 5 威海火炬八街,烟台养马岛

早上吃了当地的特色海菜包子,但是感觉到没啥特色,还是肉包子更好吃点。吃完就赶往火炬八街,但是还没走到,小朋友就被沿路的一个体感农场黏住了不愿意走。等她玩够了才继续往火炬八街走,途经的路还正在修,完全不像景区的样子,到了火炬八戒,又是人山人海,各种拍照的。在火炬八街的海滩玩了一会,就决定找个地方去吃饭了。

找了一个当地的老店,吃了个网红海鲜大咖,店里客人挺多,服务一般,不过价格也还算实惠,人走的差不多了,老板过来解释客人多服务下降望原谅。

下午赶往养马岛,本来计划走环岛路,然而前往獐岛的路在修,只好从岛内绕行。獐岛区域的海,虽然说没有达到果冻海的程度,但是也很漂亮了,应该是这几天来最好看的海面了。

随后沿岛开了半圈,景色大同小异。便决定去吃个海鲜面再看日落,然而绕路加上导航错误,吃完海鲜面已经看不到日落,岛上找了家民宿就住下了。

Day6 车祸现场,烟台蓬莱阁

早上本打算到海边再看看养马岛的海,然后看完海,倒车的时候,撞到了渔船的螺旋桨,把后挡风玻璃干碎了。打了4s电话就赶过去看了,然而玻璃也要几天时间订货修不了,就走了(也没报案,为后续修车问题留下了伏笔,等修完车再写吧)。

4s店告知修不了之后,便找商店买了透明胶带把后挡风粘上,防止后续行驶过程中,玻璃渣子掉下来。此时我们已经在烟台市区和蓬莱两地中间的一个区域了,便决定前往蓬莱去看看蓬莱阁。

蓬莱阁景区很大,附近还有很漂亮的欧式城堡和八仙过海景区,但是我们只钟情于蓬莱阁。蓬莱阁和滕王阁、黄鹤楼、岳阳楼并称中国四大名楼,自此除了岳阳楼,其他几个都打卡了。蓬莱阁建于海边,阁边观海很凉爽,景区内还有炮台,苏公祠,天后宫等建筑,也都走马观花看了看。

其中印象最深刻的是戚继光纪念馆,居然有接近一办的内容和主席有关。

本欲前往田横山看看黄渤海分界线,然后索道维修,不想爬山,便放弃了。打算回烟台市区看看烟台山景区,到达的时候,那边已经关门也只好在海边看看。顺便在虹桥1920转了转,那边的店铺都看起来比较高大上,也就未做停留。

烟台老城区,路上相当堵,驾车前往烟大小吃街附近,花了好久没找到小吃街,最后在路边吃了个烧烤,吃完烧烤终于找到了小吃街,原来也都是烧烤店铺。

Day7 日行千公里,冒雨回程

今日准备返程了,行到青岛,小鹏服务中心的人让我先报案,结果一顿折腾搞得心情不好,再加上玩了几天也有点累了,就决定直接开回家了。

过了连云港之后,就开始下雨,到南通之后,雨更加的大了,但是最终还是在晚上10点多到家了,此行也算是结束了。

总结

这是可以说是说走就走,也没列什么计划,酒店住宿也都是当天才定。 住宿的价格方面,威海和日照还算比较便宜的,青岛和烟台的价格感觉就要贵不少。同时吃饭反面也是差不多,日照最便宜,威海其后。评价海边的风景,养马岛的海水最好看,青岛和那香海的海滩最干净,烟台市区、蓬莱、威海市区的海要差一点,有一些漂浮物和海草,青岛的沙滩最干净,沙子更细腻一点。总体来说山东的沿海城市都不错,不太热,海鲜价格还实惠,是亲子出行的好去处。

一路高速上开了小鹏的NGP减轻了很多的驾驶疲劳,让我最后一天即使开了1000公里也感觉不是很累。但是最后一天ngp的时候方向盘乱晃,手打方向盘硬的问题,还是需要去店里看看。

开车去旅行,时间的安排更自由,一个地方不喜欢可以说走就走,当然出事故也也比较烦😭,总体还是方便更多。

此行花费的大头还是吃,其次才是住宿和交通费用,下次倒是可以买点海鲜自己做就会省下很多了。

虽然带了相机,手机,运动相机,结果整理照片的时候还是发现很多景点没有拍照,一是人多不想拍,二是觉得这个地方自己拍不好,归根结底可能还是技术菜吧。

六月小记

2024年6月29日 15:52

不知不觉,六月已到月底,2024年已经过半。工作上无所事事,又是摸鱼的一个月,博客也没有写一篇,想着还是要记一点东西,不然就这样又苟过一个月,又没有留下任何的记忆。

手术

手术实际上是五月底所做,做的是卵圆孔闭合手术。发现卵圆孔未闭合的原因是一直有头痛的症状,发现了上海六院有一个头痛整合门诊,结果查到了别的都没有问题,唯独卵圆孔未闭合,很有可能就是因此引起的头痛,遂进行了该手术。因为是微创手术,回家一个多星期伤口差不多就回复了,正常生活没啥影响。但是现在是夏天,术后严禁烟酒,不能喝啤酒就太难受了,只好各种法子的气泡水加冰加饮料折腾喝。另外就是不能剧烈运动,这段时间一直在家窝着,也不太敢开车出门。

手术的费用方面,医院的费用加上院外买的药总共5万元,医保覆盖了大部分,公司的商业保险覆盖了其他的部分,甚至医保个人支付的部分也给报掉了,变相的把个人医保余额给取现,因此来说保险还是起了很大的作用,还是很有必要的。

出行

因为需要静养的原因,再加上下半个月上海进入梅雨季节天天下雨,这个月机会没有出门。趁着周末在上海转了两次。一次是跟着朋友一起驾车到奉贤看海,走一走上海最美公路塘下公路。碧海金沙没有去,其他地方,也只能在堤岸上看看,海水不好看,并且也不能翻越堤坝过去。往塘下公路去的路两边水杉树好看,但是因为小朋友要睡着了,开了一会就返程了。

另一次今天,趁着今天没雨开到了青浦,逛了一下练塘古镇和金泽古镇。两个古镇都是商业化比较少的,练塘古镇就一条河和几座桥,外加陈云纪念馆,金泽古镇要更大一点。古镇皆为一条主河,河两边为民宅和店铺,河中偶尔还有一些小船,金泽是有游船的,因为饭点到达便未乘船游玩。除此之外金泽古镇还有两座小庙,为小镇更添几分热闹。但是总体而言两个地方人流都不太多。周末过来转转还不错。看完古镇又前往淀山湖吹吹风,之后惬意的回家了。

养鱼

之前给小朋友养了几只小螃蟹因为死了一只其他的怕是养不活,便全部放生了。看着网上别人养鱼手痒痒,就想着带小朋友一起养养鱼。说干就干,趁着6.18把鱼缸,水草泥,鱼缸灯等一堆东西火速买齐,收到快递后第一时间把缸给开了,当天又带着小朋友去花鸟市场买了几只斑马鱼放进去。随后几天又放了几条孔雀鱼,然而放完孔雀鱼当夜,就有两条孔雀鱼跳缸而亡。如今已过一周余,缸内已经开始长起了藻,缸内不只哪条鱼生了两只小鱼。每条小朋友来喂鱼,看鱼,给大人小孩都是找来了很多的事情干。

折腾

家里目前是用一个树莓派插了个硬盘盒,树莓派刷的openwrt,这样实现了家庭的全局科学上网,以及简单的NAS功能。但是之前自己编译的openwrt因为选择的kernel的版本的原因,许多的软件装不了,想要装docker扩展更多的功能也不行。

突然又想再折腾一下,遂重新拉了一下 ImmortalWrt 23.05.2 r27625-416c8c5c91 的openwrt,顺便把rom size改大到SD卡的剩余可用大小,这样之后根目录下面就有更大的空间方便安装更多的软件或者docker容器。

之后又分别安装了Jellyfin, Navidrome,FreshRss实现了视频,电影,RSS订阅的服务。如此下来家庭环境下就有了更好的影音体验。唯独不足的是硬盘只有2TB,拷了一些电影之后就快满了,而把另一块放到一起弄Raid0或者JBOB, Jellyfin的识别有问题,又或者拷贝大文件磁盘就Down了。想一想再要折腾就要买成品NAS或者自己买硬件组装,反正是不能用USB硬盘盒了。

读了两本书,一本马伯庸的《太白金星有点烦》,以太白金星的视角来写西游记,写出了官场职场的人情世故,相当精彩。另一本是刘易斯的《大空头》,详细记叙了在08年次贷危机前,巴黎,艾斯曼等人做空次级贷款的故事,书中有次贷是什么的记叙,有他们如何发现次级贷款存在问题的记叙,还有贪婪和傲慢的华尔街投行们。这两本书都很值得 一看。

陪着老婆看完了两部爽剧,一个是美剧《布里奇顿家族》,一个是中国的古装爽剧《墨雨云间》,两种不同的爽剧,皆有主人公甜甜的爱情,都是下饭的好东西。另外还开始看《人生复本》, Apple TV出品,内容是关于多重宇宙的,刚看了两集也不错,另外这个是根据同名的书改编的,准备先去看看书。

总体来说,这是摸鱼的一个月,工作上没做啥事情,上班时间把南大的操作系统课给刷完了,JYY讲的很精彩,关于系统调用,内核态等等各种东西,让我在看java虚拟机和协程的时候有很多地方感觉更通顺。这种讲的比较好的基础类课程还是值得我们去刷一刷的。

好的,这个月就这样结束喽。

向伟人学习-读《富兰克林自传》

2024年5月25日 20:05

最近Apple Tv上映了《富兰克林》,想到了《富兰克林自传》这本经典书还没看过,遂找到来读。书的内容大体上记述了他少年,青年,中年,以及到50多岁的事情。书的内容很好,很有启发,也有很多他的个人品质值得我们学习,看了一遍恐难以很好的对他有所了解,第二遍读完方才动笔开始写读书笔记。

生平简介

恐怕有人对富兰克林不了解,我这里简单介绍一下。他出生在一个普通人家里,父亲移民到美洲后生下他,他年少就作为一个印刷工,后来自己开办印刷所,同时发行报纸等,在殖民地他积极参与议会并担任职位,后期参与推动了美国独立,他积极投身于公共事业,提议创建了消防队,巡查队,参与创建图书馆,建立宾夕法尼亚大学等等。空闲时间还进行创新发明,进行科学实验。关于他的更多详细介绍,感兴趣的可以去看看维基百科

读书与学习

富兰克林仅仅在学校里面读了两年的书,但是他重新就酷爱读书,自己的零花钱都会拿去买书看,十二岁进入哥哥的印刷所之后有了更多的机会接触到更多不同的书,因此也有机会阅读更多的书。而之后,不管是去到费城的印刷所工作,还是在英国的印刷所过做,以及后面开了自己的印刷所,他都一直保持读书的习惯。我们可以看到在当时获得图书很艰难的条件下他仍然孜孜不倦的通过各种方法获得图书去阅读,这启发当下的我们更应该保持终身阅读的习惯。

而他看书还不是看一下就完了,书中他分享了年少时候的他发现自己的无法对于词语运用自如,便尝试把故事使用诗歌的形式来转述,即锻炼了自己运用词汇的能力,又很好的去用自己的语言去理解原文的内容。不仅如此,他会在过一段时间自己把诗歌还原成散文,把自己的与原文对比,改正自己的错误或者发现原文的错误。类似这样的用自己的语言来复述原文,并进行订正的学习方法,在当下看来仍然是很有效的方法,依然值得我们来学习。

不仅仅如此,他还擅长通过观察来学习。在他十二三岁的时候他通过观察学习工匠技术,作为一个印刷工做的比大多数的工人要好。在家的时候他也通过观察发现自己父亲的特质,已经听哥哥的朋友们谈论学习。

在十几岁的时候,他就结交喜欢读书的人,并且经常一起互相交流读书感悟,并就相关内容进行辩论。他把他的朋友们组织成一个俱乐部,互相促进,共同提高。向别人学习,从交流中学习,这也是一种很好的学习方法。

品格修养

他为自己提出了十三条的美德规诫,并且花了很长的时间来进行来培养这些习惯,书中也讲述了如何培养这些习惯的方法。规诫内容如下:

一,节制。饭不可吃胀。酒不可喝高。
二,缄默。于人于己不利的话不谈。避免碎语闲言。
三,秩序。放东西各归其位,办事情各按其时。
四,决心。决心去做该做的事情,做就做到心想事成。
五,节俭。不花于己于人没有好处的闲钱,杜绝浪费。
六,勤奋。珍惜时光。手里总忙有益之事。剪除一切无谓之举。
七,诚信。不害人,不欺诈。思想坦荡,公正;说话实事求是。
八,正义。不损人利己,伤天害理的行为永不沾边,利公利民的应尽义务切勿放手。
九,中庸。避免走极端。忍让化冤仇。
十,清洁。身体、衣着、居所,不许不干不净。
十一,平静。不可为小事、常事或难免之事搅乱了方寸。
十二,贞洁。少行房事,除非为了身体健康或传宗接代;千万不可搞得头脑昏沉,身体虚弱,或者伤害自己或他人的平静或声誉。
十三,谦卑。效法耶稣和苏格拉底。

这些品格对于我们现代人来说仍然很有用,特别是当今网络发达,社会上各种光怪陆离。他提到的一个一个的习惯养成,循序渐进,同样适用与我们养成其他的习惯。

从他做的很好事情中,可以看到很多他的好品格。经常他提出的很好的建议,他常常会说自己不是首创人或者只是合伙人之一,这无疑体现了他的谦卑。同时他的这样做法会让人感到他不居功自傲,更容易把提出的提案推行成功。

事业与财务

他从一个印刷工学徒发展到印刷商,从两手空空到通过印刷所的收入可以养活自己一家,而自己可以全身心的投入到政治,公共事务和科学研究中去。他靠着自己过硬的技术和良好的人格,获得了朋友和工友父亲的投资,使得他开始自己的印刷所,以及后面他通过与他的工人合伙创建更多的印刷所,实现了钱生钱,利滚利。

这本书上我们可以看到一个爱读书的年轻的奋斗史,他有很多的地方值得我们学习。当然,他写书本身也是想通过自己的经历来劝诫年轻人,可能他的一些美德有被强调,这倒是方便我们来关注到。 到这个年纪才读了这本书也是我的一大遗憾,这本书已经是中小学必读书单之一了,我也是强烈建议中学生都能读一读。学习富兰克林的美好品德,学习他爱读书的习惯,学习他的学习方法。

最后推荐大家亲自阅读。

一个Android开发者的Google IO 2024信息汇总

2024年5月21日 21:53

AI和大模型很火,今年的google io上面感觉各个方向都和AI有关,Android平台相关的东西倒是感觉不太多了。我这里整理一下Android相关的信息。Android主要就是Android 15的发布,以及jetpack compose的更新和google play的一些更新。

AI与Android

Android 14开始手机会内置Gemini Nano,开发者可以通过AI Core来调用AI的能力,目前是google pixel 8 pro和三星的s24已经内置了。除了端上,开发这还可以使用Firebase新提供的一些能力使用AI模型。

对于开发者来说,除了开发应用提供AI能力给用户,开发过程中也能体验到google提供的AI能力,下载Android Studio Koala即可使用,提供了类似github copilot的功能,有代码补全,自动代码生成,对话生成代码,UI设计图生成代码,代码重构等功能。

Android 15

每年一个大版本现在是Android系统的惯例了。google io开始的这天发布了Android 15 Beta2。

摄像头方面引入了低光增强功能,这个对于国产手机拍照功能基本都是已有功能,不过对于开发者可以通过Camera2的接口来使用相机提供的这个功能。同时还提供了新的闪光等强度控制API,在支持的设备上更好的控制相机硬件和算法。

文字方面,中日韩语的字体,android上的是NotoSansCJK,新的版本将是可变的了,这代表可以中文可以有更多的样式和变化了。Android 15开始,可使用 JUSTIFICATION_MODE_INTER_CHARACTER 利用字母间距将文本两端对齐,Android 8.0引入了字词间对其,这对于中文这种单个字符的语言是不友好的,新的字符间对其可以大大改善中文排版的美观度。Android 15中还提供了标记来控制换行,即 <nobreak>来避免换行,<nohyphen>避免断字。

<resources>
    <string name="pixel8pro">The power and brains behind <nobreak>Pixel 8 Pro.</nobreak></string>
</resources>

未使用nobreak使用nobreak

对于GPU的使用,Android在7.0的时候引入了Vulkan,在今年他们有引入了ANGLE,这个对于普通开发者不需要关注,对于游戏开发者或者需要使用Open GL进行图形处理的需要注意,毕竟Google计划未来只支持通过ANGLE使用Open GL。

预测性返回动画之前在android14中就有了,但是需要在开发者模式中手动打开,普通用户还用不了,现在默认打开了。

最小target sdk version提高到24,低于此版本的将无法在Android15的手机上安装。

另外关于前台服务,隐私空间,系统UI等方面也有一些提升和新功能。更多内容可以看Android 15的文档: https://developer.android.com/about/versions/15/summary

Kotlin和Jetpack compose

Kotlin 主要介绍了jetpack的更多库适配了kmp,让开发者可以在更多平台共用代码。具体可查看文档:https://android-developers.googleblog.com/2024/05/android-support-for-kotlin-multiplatform-to-share-business-logic-across-mobile-web-server-desktop.html

Jetpack compose支持了share elements 动画,列表动画,Text支持链接和html富文本而不必使用ClickableText,以及一些性能提升。当然,最大的变化应该属于在kotlin 2.0的时候,compose的编译器将从谷歌的代码库移到kotlin的代码库,对于我们来说这意味着compose的编译器插件版本将和kotlin一样,减少我们升级版本的很多烦恼。更多详见:https://android-developers.googleblog.com/2024/05/whats-new-in-jetpack-compose-at-io-24.html

同时Compse对于更多尺寸的屏幕,以及手表,电视等等有了更好的支持。compose adaptive 库提供了一些api来让我们更多的适配各种屏幕尺寸,主要的是NavigationSuiteScaffold, ListDetailPaneScaffold, SupportingPaneScaffold。这次大会更新了Compose for wearos 的库,让更多功能稳定下来。正式发布了Compose for TV的1.0。这样下来所有的Android 平台都可以使用Compose进行开发了。

我们的桌面小组件,也发布了Jetpack Glance 1.1,来让我们支持使用Compose来编写桌面小组件。当然其中的一些widget和普通compose拥有一样的名称,但是却来自不同的package,因为最后还是会编译成remoteview,因此不能混用。

由此可见Android的原生开发以后将是Compose的天下,加油学吧。

Flutter

Dart支持了宏,从而对于Json的序列化和反序列化会更加简单。具体的使用方法: https://dart.dev/go/macros

Flutter 通过WebAssembly在浏览器上面运行性能更好,因此官方后面在Web的方向应该是WebAssembly了, 对于Flutter转js这个方案应该会被放弃。

Google Play

谷歌正式放出了隐私合规检查工具 Checks,可以帮助我们检查app的隐私合规的问题,检查app收集的用户数据,使用的权限,sdk等等,在当前各个国家对于隐私政策越来越严的当下,这个东西挺不错的。访问官网了解:https://checks.google.com/

谷歌在2021年发布了Google Play SDK Console给一些大的SDK开发者,现在这个Consle开放给了所有SDK开发者,借助这个平台SDK开发者可以在sdk有漏洞或者安全问题时,让使用到sdk的用户在谷歌得到通知来升级sdk。同时还可以查看sdk的用户数据,以及让应用开发者共享sdk的崩溃和卡顿日志给sdk的开发者,从而更快的解决问题。

谷歌还发布了Engage SDK, 帮助开发者在google play 内展示app的内容,吸引用户使用我们的应用,但是这个SDK需要开发者在媒体体验计划中或者应用用至少100K的DAU才能申请。当然除了这个sdk,新的google play还支持我们使用搜索关键定制商店详情页,这样可以对不同的来源做定制,提高用户下载app的转化率。应用详情页之前只能展示针对当前设备的屏幕截图和介绍,新版本将支持展示所有支持的设备的信息。

Play Integrity API也有更新,新增加了应用访问风险检查,服务端接口也可以使用play protect的验证。

新版本的Google play后台中还支持对于Deeplink 的管理,通过Google play甚至可以变更deeplink, 而不用更新app。

更多的内容还是请参考官方内容:

Android系统的更新:https://developer.android.com/about/versions/15/summary

Android Studio 的更新: https://android-developers.googleblog.com/2024/05/google-io-2024-whats-new-in-android-development-tools.html

Google Play的更新: https://android-developers.googleblog.com/2024/05/io-24-whats-new-in-google-play.html

Compose的更新: https://android-developers.googleblog.com/2024/05/whats-new-in-jetpack-compose-at-io-24.html

Flutter 更新: https://docs.flutter.dev/release/whats-new

看皖南山水-皖南川藏线及查济桃花潭自驾游

2024年5月8日 20:42

皖南常去,但是很多景点一直没去过,特别是皖南川藏线和查济古镇一直心心念念了好久了,这次趁着五一自驾转了一圈。因为遇到下雨,此次行程耗时三天,很多地方匆匆而过,因为而且还没到玩水季节途中的很多漂流景点也未开放。一路山看山看水,看古镇,整体体验也还不错。 黄山太平湖

Day1

上海出发从宁国下高速,一路还比较通畅,两个多小时就到啦。给车子充满电,去网友推荐的餐厅吃个饭,就驶向皖南川藏线的东入口了。

第一站去了储家滩,路的一边是山一边是河,风景不错。第二站到达青龙湾观湖驿站,有一个看湖的观景台。山上的惠云禅寺是观青龙湖的好地方,但是考虑到绕一下可能看不到日落就没过去了。

落羽杉观景台的上山台阶

落羽杉

再往后走到了落羽杉观景点,有一个观景台需要从停车点后面爬上去,上去之后可以看到旁边的水杉林和河流,由于河水水位下降风景略有一点差。后面还有小岭头云烟山野不好停车就没下来看了。在去往幸福路观景台的路上看到一些猴子,不过不好停车也就直接走了。幸福路观景台和六道弯这一段的路就有很多的弯道了,真的是川藏线的体验了。

幸福路观景点

六道弯看夕阳

六道弯夕阳

六道弯咖啡店

到达六道弯正好太阳下到了山顶,夕阳倒是让我拍到了。时间不早就直接下山,后面的几道弯都没有停留了。下山后在苏红村找个民宿,炒两个菜,喝点酒,然后就帮着蛙声睡下了。

Day2

早上醒来,因为刚下完雨,外面的山顶浓雾笼罩,空间也很清新,打开窗户神清气爽。

水墨汀溪

水墨汀溪

吃完饭就启程前往漕溪花海,然而除了一些茶树啥也没看到。转而去了水墨汀溪,因为还没到时间,景区还不收费,车子可以直接进去。里面的景色还可以,溪流玩水也很不错。就是没来对时间,还没到漂流季节,内有皖南蜀道,小朋友直接被吓退也就没去了。准备去来就月亮湾家下起了大雨,路上买了点当地的茶叶带着。到达月亮湾雨还没停,也是没法玩了,就继续前行前往查济古镇了,路上找了一家土菜馆把午饭解决掉了。

查济古镇

到达查济古镇,雨也停了,景区门口的民宿老板招呼着,就开车进景区看了看民宿环境,把晚上的住宿解决了。听了老板的建议,随后就走到河边开始探索查济古镇。转了个大概又开始下雨便回去了。

Day3

早上吃完饭,准备在景区再转一圈,遇上了一大波过来春游的中学生,原本显得很冷清的景区热闹了许多。把财神敲我,红楼桥,二甲祠都又转了一下,买了点板栗饼就启程前往桃花潭了。

文昌阁

中华第一祠

南阳古镇

把车子停在啦桃花潭游客中心,随后便进去了,首先看到的桃树已经结了果,油菜也马上可以收割了。先去看了文昌阁,中华第一祠,南阳古镇,随后坐船到达对岸。坐船就能看到桃花潭了,桃花潭不是我们想象的一个湖,其实是青弋江中的一个点。湖对面是万村古街,河边的亭阁是个观潭的好地方,旁边还有汪伦墓。随后坐船回对岸,走到停车场,这时发现车子如果停在水东老街出口这里会更方便。

南阳古镇

踏歌楼

桃花潭

汪伦墓

本想继续在玩一天,老婆觉得有些累了,就决定开车回老家了。经过太平湖就找了方便停车的地方在这边转了转 湖水很绿,周围有山 风景很不错在湖边露营应该很惬意 看完湖就开车回家了。

其他

最后再说说电车充电的问题,车子满电400公里没啥问题,目前的单程 500 公里内的基本不成问题。上海到宁国不需要充电就到了,进皖南川藏线之前利用吃饭时间把电充满了。几个地方玩玩之后,在回老家的路上利用休息时间把电充满。总体来说,车支持快充,再加上利用服务区休息和吃饭的时间,基本上不浪费时间。

另外玩的过程还拍了一些视频,分别是: 皖南川藏线游玩视频:

查济古镇以及周边视频:

记国产手机无法在Chrome使用Passkey问题解决

2024年4月23日 20:30

众所周知,在国产Android系统上面,Google play service是被阉割掉的。部分厂商提供了打开google play service的选项,让我们可以登录google 账号,使用Google play store,以及部分的Google 云服务,但是Google password manager以及Credential Api确是没有的。在Android手机上面,Passkey是依赖于GMS和 Credential Manager API的,因此,国行手机上面也就没法使用passkeykey。不过使用Chrome浏览器的话,还是能够使用Passkey的,这是因为Chrome提供了相关的实现。然而,前几日Chrome升级后,我的Passkey突然就不能使用了。

首先尝试了重新卸载重装Chrome,手机的google账号管理里面测试passkey等等,结果还是不行。最后只得尝试在Google搜索,找了很多,发现了这样一个页面How do I use Passkeys in Google Chrome on Android?, 其中介绍的是如何在android手机上使用1password。其中关于chrome的flag部分引起来我的注意,因为Android 14后开始支持使用除了google password外其他的应用提供的passkey功能,所以我猜想可能是因为这个,google 最近改动了chrome关于passkey的逻辑,默认会使用手机系统的Credential Management Api而不是Chrome自己内置的Api。尝试了一下把这个Flag改为Disabled, 重启一下Chrome,Passkey又工作正常了。

操作方法为Chome地址栏中输入:

chrome://flags

然后搜索Passkey,出现这个条目之后,修改其设置。

另外还要说一下,虽然Chrome中的passkey使用问题解决了,但是因为手机内没有Credential Manager Api,应用还是没法使用passkey的。除此之外,通过手机扫码,让电脑使用passkey的时候,也会一直处在连接中,最后也会失败,目前这个也无解。因此,如果想要顺畅的使用Passkey只要两个解决办法,一个方式是换iPhone,另一个方法是买一个海外版的Android手机,比如Google 的Pixel,三星,或者尝试一下海外版本的ROM。

我的个人密码存储与管理

2024年4月8日 19:13

作为一个网民,使用每个服务都需要注册账号,而注册账号就需要设置用户名和密码。在早期,我会将所有的密码都设置成相同的,这样方便自己记忆,每次输入密码也都很方便。

很久之前的一个同事,他会将自己的所有密码都记在一个小本本上。彼时,一些使用iPhone的朋友已经开始使用1Password来存储自己的密码了。而我,作为一个坚定的Android用户,此时还没有使用过任何的密码管理软件的。

直到某一天,Chrome提醒我我的密码已经泄露不安全了。此时便开始研究适合我的密码管理软件。 最终选择了Keepass作为我的密码管理软件。

经过几年的使用,使用的软件终于稳定下来了,在此分享一下。

目前我需要查看软件的平台有三个Mac 电脑, Windows台式机,以及我的Android手机。 Android手机我使用的是:Keepass2Android ,windows和mac下使用的是 KeePassXC。密码库是一个kepass文件,可以理解为一个加密数据库,必须通过主密钥才能打开。客户端本身不提供密码的多平台同步功能,我本人使用了坚果云来存储kepass文件,Android手机上keepass2Android通过webdav访问和同步密码库, 电脑上使用坚果云的客户端来同步密码文件。

密码管理工具首先能满足的功能就是创建密码,三个平台的客户端都能自动的生成密码,并且允许配置密码的字符,长度,密码安全等级检查,软件也支持过滤弱密码。

一个做的比较差的密码管理工具,是需要用户在每次输入密码的时候都打开密码管理工具,来复制密码回去再进行粘贴的。这方面1Password做的是最好的,有很多的自动输入或者选择来提高易用性。kepass的客户端当然也是有的。

Android客户端首先是支持Android系统的自动填充服务的,Android 8.0以后的手机就支持,需要在系统设置中设置自动填充服务为Keepass2Android,同时密码保存的时候要保存当前这个应用的package name这样才能自动填充对应的密码。当然也可以先搜索到这个密码后,软件会保存package name,下一次就可以自动选中这一条密码了。对于不支持自动填充服务的手机,或者应用开发者关闭了自动填充,也可以输入的时候把输入法切换为keepass2Android(前提需要在系统的输入法中启用keepass2Android的输入法)。

对于电脑上面,可以通过浏览器插件来实现密码的自动填充,目前edge,firefox,chrome都有对应的插件,可以在上面的链接中找到。对于网页的自动填充,还需要在创建密码的时候,把网址填到密码信息中。

国内的大部分账号目前都是短信验证码登录,用不到密码。另外一些银行或者金融类的限制了自动填充,甚至自己写了个键盘,还是只能切到密码管理器去看密码再回来手动输入进来,短期内也不会有所改善。

总体来说,目前大部分的重要密码都保存到了keepass中,文件也是自己管理,比1password这种托管的更放心一点。目前海外已经开始使用passkey来替代密码,相信未来密码的使用会越来越少。

一场美食美景之旅-记成都重庆游

2024年3月24日 22:03

重庆和成都一直在旅游清单的列表中,月初朋友提议一起到成都走一走,想着三月份是成都重庆的旅游淡季,遂买了机票规划了这次的旅行。

四姑娘山双桥沟

行程计划

出发前先制定了此行的规划:

Day1 到达成都天府机场,换成地铁到达市区,住下,周边转转

Day2 去春熙路,ifs 熊猫拍照,人民公园,宽窄巷子,武侯祠,锦里,看川剧

Day3 租车去都江堰水利工程,卧龙中华大熊猫苑神树坪基地,四姑娘山镇

Day4 去四姑娘山双桥沟景区参观,驾车到成都东站还车,乘坐高铁前往重庆

Day5 山城步道->解放碑->十八梯->白象居->来福士->洪崖洞

Day6 鹅岭二厂->李子坝->长江索道->弹子街->重庆江北机场

订酒店的时候才发现原来成都在搞糖酒会,酒店价格都快翻倍了,于是设计了一个只在成都住两晚的行程。

Day1

到达酒店后,就看到附近很多的串串火锅之类的店,因为很累就在酒店旁边的肥肠鸡和串串店开吃了,配上啤酒相当爽。

酒足饭饱后,又跑到了春熙路和太古里看了看,熊猫雕塑打个卡。

Day2

早上起来在酒店旁边吃了千里香馄饨就前往人民公园去吃早茶了,发现都是游客😄。 人民公园离宽窄巷子不远,步行就过去了,成都各种熊猫饰品玩具是真的多,到处都是。 在宽窄巷子顺便看了个川剧变脸,虽然不咋样,但是也算体验了一下。

下午去武侯祠转了转,了解了一些三国的文化,想要更深入的了解还是请个导游更好点。这里的红墙道路很适合拍照,帮老婆孩子拍了几张,这里就不发了。武侯祠出了门就是锦里,这里和宽窄巷子看起来差不多,转了一会就走了。随后打车去了九眼桥,在附近吃了个老妈蹄花。待到夜幕降临,看看夜景,感受一下九眼桥酒吧街也不错(可惜带着小朋友没法去酒吧)。

Day3

因为行程比较赶,提前一天去取了车,早上早早的出发了。首先到达都江堰,这是雄伟的水利工程,当天还在进行大修,但是看起来比较枯燥,看完抓紧去下一个地点。

之后去了卧龙神树坪大熊猫基地,这里的游客比较少,大熊猫们都很在线,很活跃,小盆友们很喜欢。

随后驱车前往四姑娘山镇,路上随着海拔的提升感受到植被的减少,到达三千多米的海拔后居然下起了雪,为此相当失落想着在后面的猫鼻梁观景台应该是看不到雪山了。 随后下车方便,小跑了两步,明显感受到头晕头疼,遂放慢了脚步。之后穿过巴朗山隧道,发现隔了一座山居然是两种风景,一边是大雪纷飞,另一边却是晴空万里。到达猫鼻梁观景台,顺利看到雪山,由于时间关系未在这里等待日照金山,算是一点遗憾。

Day4

提前知晓了双桥沟景区是看不到四姑娘峰的,便选在长坪沟住,但是前天晚上下雪了,但是还是没有看到四姑娘峰,略有遗憾。 早上乘坐观光车,到达双桥沟的终点红杉林,一路上白雪皑皑,终点处还正下着雪。地上,树上都是雪,远处的山上也是雪,确实美丽。

从终点回来途中的景点,又有不一样的体验。

中间又几个措(湖),是拍照打卡的好地方。

观光车上山差不多就一个小时,还要回成都去重庆,时间还是比较赶的,再加上朋友高反有点严重,7个观光点就没有全去,之前别的游客推荐的一个很美的拍照点也没去,这个遗憾只好下次有机会再来补了。

之后便开车赶回成都前往重庆,一路开车还是比较累的,山路各种U形弯相当刺激,油车加速不给力,上个坡踩油门都没反应。但不管怎么说,晚上还是顺利到达了重庆。

Day5

睡了一觉起来后才感受到重庆的3D地形,明明是负一楼,电梯出来居然是外面的道路。明明爬了几层楼,出来居然是马路。住在解放碑不远处,出门就打卡解放碑。

中午吃火锅,朋友推荐的店在装修没吃到,便利店的阿姨推荐了旁边巷子里的火锅,真的好吃又便宜。

下午去山城巷,十八梯,感觉重庆哪有什么旅游淡季,不是节假日,还是工作日,每个地方都有很多人。

晚上去了洪崖洞,拍拍夜景,桥下的一片水洼映出的洪崖洞倒影非常出片。

Day 6

打卡李子坝地铁穿楼,依然很多人。

随后去了鹅岭二厂,很文青,比较适合拍照。中午吃了个江湖菜,是个川菜大集合,😄。 下午看了看朝天门和湖广会馆,就前往机场打道回府了。为什么没去长江索道呢,当地人建议不去,又要排队就放弃了。

总结

除了照片还做了个视频。

成都和重庆的美食确实多,晚上11,12点,八一美食街和其他的各种好吃街都还有很多人,虽然人多,但是下次还要来。 四姑娘山这次只留了一天时间,还没玩够,下次有机会再来体验一下长坪沟听说很刺激。 重庆人好热情,不认识的人会给你推荐好吃的店,出租车和网约车司机也不坑,给你有用的建议。去机场的司机还热情带看了重庆的盘龙立交。 古街古镇感觉都差不多,在重庆就没去了,也不推荐去,去重庆专注吃就行了。

历史之城英雄之城-南昌游记

2024年2月23日 18:44

春节的时间比较长,不出去玩一趟就感觉没有过完整似的。今年依然选择了江西,因为江西的城市离得近,开车就能到了。本打算去庐山,但是查了一堆攻略,临行前一晚又改到了南昌。南昌更远,不过也更加平价,老城区的建设比较慢,好吃的很多,总体还是很满意的。

第一天 - 滕王阁

驾车出发,下午2点多到达南昌,直奔滕王阁,因为堵车在外围转了一大圈,只好先定了酒店前往住下。

酒店出来,直奔蛤蟆街搞了点吃的。首先就就是南昌知名的水煮和油炸,水煮和麻辣烫感觉差别不大,油炸虽然和我们老家的油炸很像,但是配着他们的调料又感觉很不相同,这个调料真的很好吃。

吃饱之后,直奔滕王阁,然而来的太晚了,售票已经结束,在滕王阁公园和赣江边转了转。

随后,跟着人群来到了东门,这里很是热闹,有漂亮的灯笼,有很多摊贩。在这里购买了《寻梦滕王阁》实景表演来夜游滕王阁。

夜幕降临,滕王阁前面这条路上的灯亮了,此时可以看到很多诗句,譬如“落霞与孤鹜齐飞,秋水共长天一色”,相当有意境。

晚上观看实景表演,下着小雨,不过表演效果不错,通过表演看到了特技表演,也了解了许多之前不了解的关于滕王阁的历史和文化,也是值回票价。

随后夜登滕王阁,了解了更多关于滕王阁的历史,以及与他有关的人,以及江西的一些文人文化。登上高阁,也一赏赣江两岸的夜景。

第二天 - 寻觅英雄足迹

第二天一早,骑着共享电单车我们就直奔八一广场去了,想说去看一看八一纪念馆了解一下南昌起义的历史。然后后来发现需要预约,今天已经约不到了。只好在八一广场看了看相关的雕塑和介绍。

随后去到了隔壁的江西美术馆,美术馆的设计很红色,和八一广场很搭。展馆中的展览,有关于八一广场的,也有红色主题井冈颂,最令人印象深刻的是《虚拟与重塑》相当的现代和科幻。

午饭后去新四军旧部遗址看了看,了解一下新四军的发展历程和革命历史。

最后,我们到访了万寿宫历史文化街区,这里的街是很繁华,人是超级多。

第三天 - 看江博

第三天我们早早来到了江西博物馆,展馆中的特展御瓷归来相当惊艳,展品大多是从故宫博物院和景德镇御瓷博物馆借来的,布展精美拍照很好,我只顾着看了,就没怎么拍。

另外二楼的江西历史文化展,对于江西的历史有了更详细的了解。

从博物馆出来,去取车的路上又经过了建军雕塑广场,此处可以看到南昌老城区,又有一些建军相关的雕塑。

随后,吃完山寨老三样,即踏上归途。

南昌体验

南昌老城区的房子能够感受到历史感,红砖墙面,镂空花纹,以及各种不同样式的又年代感的建筑。而改造后万寿宫历史街区又与老房子形成鲜明的对比。

南昌的美食很多,虽然没有吃到正牌老三样,山寨店感觉也很不错,点了几个菜每个都好吃。另外,南昌的早餐有好吃的拌粉和瓦罐汤,而且很便宜,一份粉只要5块钱,只要上海四分之一的价格。除此之外,羊子巷,蛤蟆街,士大夫院街也有很多好吃的。但是如果不能吃辣,就很多东西吃不了了,南昌的辣感觉真的是湖南和四川没法比的。

总结

南昌的人真的多,本以为春节假期的尾巴过来回人少点,结果还是看人从众,看表演都还是加座区,吃饭排不上号。不过话又说回来,吃饭也没必要去网红店,其他店也很好吃的。

南昌有地铁公交,短途可以骑电单车,交警管的也管的很松,体验不错。反倒是驾车在老市区挺麻烦的。

另外开着电车过来,一路300多公里基本也不用充电,中间休息的时候补个电也节省时间,去看博物馆的时候,把电充完,回程也无忧。

此一行,对江西的历史文化了解更多,也吃到很多江西美食,很满足😋。

2023年个人总结

2024年1月24日 23:30

柿柿如意 图: 明明 又是一年的结束,又是一年的开始,看到很多人写了年度总结,才想到我的年度总结还没有写。终于马上要到农历新年了,匆匆动笔。

工作

对于身处的行业和公司来说是起伏的一年,行业经历了公司爆雷公司破产,我们公司也受到重挫。我们公司也裁员了三四波,到年底我们组的人数只有原先的一半。因为经历了几次需求做完最后又不上线了,很多人也从年初的干劲满满,到后期的无所事事,消极怠工。每次要裁员的消息传出之后,我也很是忐忑,一方面是现在的整体大环境不好,找工作难,另一方面是个人的落户等等方面会受到工作的影响。

给自己过去一年在工作能力和技术方面的评价,个人认为是成长很少的。今年所做的东西方面欠缺挑战性,个人在技术学习上所花的时间很少。

2023年是AI火热的一年,各种大模型得到应用,在我的工作中,Github Copilot极大的提高了编程的效率,一些模板性的代码,它能够自动补全,一些常见的写法它也能够自动生成。ChatGPT在很多场景下可以代替搜索引擎,给到的结果更加精准,减少自己搜索时候的筛选过滤时间,在学习新的编程语言和用法时也很好用。相信经过几年的发展之后,相关的技术会越来越好用。

个人成长

在个人成长方面有一些习惯在这一年还是做到了保持和延续。

首先是英语的学习,公司提供了italki英语课程,目前还在持续跟着两个老师在练习,虽然英语依旧蹩脚,但是学总比放弃要好很多。

今年依旧在坚持读书。订阅了《读库》,上面的一些内容写的很多不错,总体来说每两个月一期的MBook都读完了,内容总体来说是纪事纪实的,内容相对小众,收获了很多的新知识。一般都是在零散的时间来阅读这些东西,我认为花时间在这个上面比刷抖音短视频要好很多,因此今年依旧继续订阅。

另外今年的阅读种类更加丰富了,除了读库内容外,还有在微信阅读上看了大量内容,包括人物传记、小说,金融题材,心理学题材,个人成长等。人物传记读了毛泽东传、马斯克传,还读了李光耀观天下,这本不是传记但是可以感受到李对世界格局的观察。金融书籍看了聪明的投资者、查理芒格的穷查理宝典、金钱心理学等,增加了一些投资理财方面的知识,还从书中学到大师的智慧。心理学内容看了被讨厌的勇气,幸福的勇气等,计划阅读阿德勒作品,但是一直没看。今年读到的比较有意思的小说是马伯庸的《长安的荔枝》,记叙有趣,让人一次性读完,仿佛回到了当前,同时书中又记叙了官场的斗争,人与人之间的相处等等。个人成长方面,看了《纳瓦尔宝典》,《技术人的管理之路》等。

年初的计划是读到的好书要写读后感记录,然后写了两篇后面就半途而弃了。写文章对于我来说还是一个比较耗时的事情,写读后感就更是如此了。一本好书,通常断断续续要个把月才能看完,看完之后内容就忘得七七八八了,需要花时间来整理,写读书笔记,在整理成文章是更加耗时的。因此,写了两篇就没写了。另外,这也可以说明做事容易三分钟热度,读书笔记和博客在下半年都荒废了。

生活

健身这一块,去年因为摔伤一次加上腿部不舒服,医生不建议锻炼,之后就一直没锻炼了,甚至好了之后也就懒得去锻炼了。一件事情放下容易,再捡起来就不容易了😅。

在年初就开始关注各家厂商的新车,并且去看了上海车展,最后买下了一辆小鹏G6。买车之后,增加了很多的开销,也增加了很多的烦恼,包括车剐蹭到了,小区停车难,但是总体来说还是增加了很多的便利。开着车子回老家,虽然时间上更长了,但是时间安排更加自由。开者车子带着家人出去玩,也不用赶时间了,并且也可以更少的做攻略。买车之后,带着老婆小孩,出去玩了几次,总体体验不错。

游玩方面,年初去了一趟景德镇,年中去了安徽的宏村,池州的蓬莱仙洞,看到了徽派建筑,玩水玩到尽兴,大人小孩都开心。年底去了一趟福建,去了海岛,吃了海鲜,还看了福建的特色建筑。因为买了大疆Action4,所以用视频记录下来了,并且放到了B站,不过所拍摄的照片却都还没有整理,游记也都没有写。

乘风启航 图: 明明

总结

这一年相对来说还是比较平淡,很多事情还是没有坚持下来,比如写博客,持续的技术学习,健身等。在年初这个时间点还是要立一下Flag,至少保证上半年是能够坚持的,如果能够坚持到全年就更好了。换另一个角度来说,如果有可能,今年还是要在半年或者季度的时候来做总结,从而保证持续把一些事情坚持一整年。

2024年,还是要继续保持阅读,坚持写作,多多陪伴家人,多多与朋友交流。

Passkey在Android端的应用实践

2024年1月17日 23:02

Passkey,中文名通行密钥,他是WebAuthn的一部分,由FIDO联盟开发,可以做到让用户不使用用户名和密码,来直接验证身份。在2022年的WWDC上,Apple正式宣布了对Passkey的支持,当前10月份,google也宣布了对于passkey的支持。目前已经有一些应用支持了passkey,包括谷歌,微软,github,whatsapp等。最近在我们的Android应用上集成Passkey踩了很多的坑,简单记录一下。 Passkey

Passkey原理简介

简单来说,Passkey就是通过密钥对验证替代密码验证,原理和SSL/TLS验证类似,密钥对即公钥和私钥。用户的设备上存储的是私钥,创建的时候会将公钥发送到服务器端进行存储。验证的时候,服务端发送一段通过公钥加密的options信息,设备端使用私钥解密后回传给服务器,则能够验证成功。设备上的私钥需要验证用户的指纹、faceid或者yubikey才能使用。 Android系统需要Android 9.0以后,iOS系统需要iOS116以后才能支持,除此之外,Android设备需要登录google 账号,并且手机上有google play service才行,iOS需要开启iCloud 钥匙串。Appple 和 Google 还会通过他们的Cloud来帮助我们在多台设备之间同步同一个用户的身份验证,从而可以让我们实现同一个passkey在同一个用户的多台设备使用。 具体到Android系统,首先需要用户的手机系统在Android 9.0以上,我猜测这是因为在Android 9.0之后要求手机要有安全硬件,放到StrongBox的密钥必须是放到安全硬件中的。web用户可以在手机的chrome浏览器中使用passkey。对于Android应用则需要用户手机上安装的最新的(至少是2023年版本的)Google play service,且手机上的play services不能是中国特色的阉割版本,否则google password manager不能使用,应用也不能够使用Passkey。对于Android 14以后的系统,应用是可以使用第三方密码管理器的,不过我还没有实践,这里不做讨论。

Android应用接入

Passkey验证流程 在Android中接入Passkey其实是比较简单的,具体是有两个场景,分别是创建Passkey和验证Passkey。

准备工作

为了让Android系统能够识别我们的应用支持Passkey,需要在我们的后端服务器中配置我们的Digital Asset Links JSON文件,这个文件如果我们配置过Android的App Links支持,应该是已经有的,这个文件的路径应该为https://example.com/.well-known/assetlinks.json,配置的内容如下:

[  
	{    
		"relation" : ["delegate_permission/common.handle_all_urls",      "delegate_permission/common.get_login_creds" ],
			"target" : {      
				"namespace" : "android_app", 
				"package_name" : "com.example.android",
				"sha256_cert_fingerprints" : [
				SHA_HEX_VALUE
				]
		}
	}
]

其中的relation用来指定声明的关系,handle_all_urls就是指可以让app处理所有的app links, get_login_creds指的是处理登录验证。 target是表示该声明应用到的目标,namespace指定为android应用,package_name为我们应用的包名,sha256_cert_fingerprints为应用的签名SHA256。 这个文件放到我们的服务器,需要保证访问路径,跟我们前面说到的一样。并且请求返回的Content-Type为application/json。如果我们的服务端有robots.txt文件要配置允许google去访问该文件:

User-agent : *
Allow: /.well-known/

Google为我们提供了Credential Manager 来使用Passkey,需要添加如下依赖:

dependencies {
	implementation("androidx.credentials:credentials:1.3.0-alpha01")
	implementation("androidx.credentials:credentials-play-services-auth:1.3.0-alpha01")
}

上面第二个依赖,如果我们是只支持Android 14以上,且不用谷歌的密码管理器,可以不用。 Proguard文件中需要添加如下内容:

-if class androidx.credentials.CredentialManager
-keep class androidx.credentials.playservices.** {
  *;
}

创建和验证Passkey都需要CredentialManager,创建方式如下:

val credentialManager = CredentialManager.create(context)

创建Passkey

创建Passkey 创建Passkey的流程如上图所示,首先需要从服务端的接口拿到一些数据,把这个作为requestJson创建CreatePublicKeyCredentialRequest去调用创建Credential,代码如下:

val createPublicKeyCredentialRequest = CreatePublicKeyCredentialRequest(
requestJson = requestJson,
preferImmediatelyAvailableCredentials = true/false
)
coroutineScope.launch {
	try { 
		val result = credentialManager.createCredential(
			context = activityContext,
			request = createPublicKeyCredentialRequest
		)
	} catch (e: CreateCredentialException) {
		handleFailure(e)
	}
}

上面的requestJson是我们从服务端拿到的,他应该是符合WebAuthn标准的json内容,prefImmediatelyAvailableCredentials, 如何设置为true,手机上没有可用的passkey注册提供者会直接报错,而不是看有没有混合可用的passkey。requestJson的demo如下:

{
  "challenge": "abc123", //服务端随机生成的字符串,用于后续判断客户端回传,用于避免被攻击
  "rp": {   //Replay party信赖方试题,用来表示应用信息,id为域名,需要和wellknown用的域名相同
    "name": "Credential Manager example",
    "id": "credential-manager-test.example.com"
  },
  "user": {  //用户信息,id和name不能缺少,displayName是可选的
    "id": "def456",
    "name": "helloandroid@gmail.com",
    "displayName": "helloandroid@gmail.com"
  },
  "pubKeyCredParams": [  //公钥凭据支持的算法类型和密钥类型,这个在webAuthn网站上可以找到相同的文档
    {
      "type": "public-key",
      "alg": -7
    },
    {
      "type": "public-key",
      "alg": -257
    }
  ],
  "timeout": 1800000, //验证超时时间,毫秒
  "attestation": "none",
  "excludeCredentials": [ //可选项,排除的凭据,可通过这个来限制不让同一台设备设置多个passkey
    {"id": "ghi789", "type": "public-key"},
    {"id": "jkl012", "type": "public-key"}
  ],
  "authenticatorSelection": { //设置支持的类型
    "authenticatorAttachment": "platform", //platform就只支持手机内置的,若为cross-platform就可支持usb的验证,yubikey等
    "requireResidentKey": true, //设置为true,则可检测到的凭据会将用户信息存到passkey中,并可以让用户在进行身份验证时选择账号。
    "userVerification": "required" //用于设置使用设备屏幕锁定功能进行用户验证,默认是preferred,用户可以跳过,建议设置为required。 
  }
}

以上json更多的解释可以看webauthn的网站: Web Authentication: An API for accessing Public Key Credentials - Level 3 (w3c.github.io)

我们客户端调用createCredential方法后拿到的结果,类似如下:

{
  "id": "KEDetxZcUfinhVi6Za5nZQ", //创建的passkey的base64网址编码id,需要后端存储
  "type": "public-key", //此值始终为public-key,不过ios手机上可能为passkey
  "rawId": "KEDetxZcUfinhVi6Za5nZQ", 
  "response": {
    "clientDataJSON":   "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoibmhrUVhmRTU5SmI5N1Z5eU5Ka3ZEaVh1Y01Fdmx0ZHV2Y3JEbUdyT0RIWSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOk1MTHpEdll4UTRFS1R3QzZVNlpWVnJGUXRIOEdjVi0xZDQ0NEZLOUh2YUkiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZ29vZ2xlLmNyZWRlbnRpYWxtYW5hZ2VyLnNhbXBsZSJ9", //ArrayBuffer编码的客户端数据
    "attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViUj5r_fLFhV-qdmGEwiukwD5E_5ama9g0hzXgN8thcFGRdAAAAAAAAAAAAAAAAAAAAAAAAAAAAEChA3rcWXFH4p4VYumWuZ2WlAQIDJiABIVgg4RqZaJyaC24Pf4tT-8ONIZ5_Elddf3dNotGOx81jj3siWCAWXS6Lz70hvC2g8hwoLllOwlsbYatNkO2uYFO-eJID6A" //arraybuffer编码的证明对象,包含rpid,标志,公钥等
  }
}

我们需要将这个json回传给服务器端,服务器会从其中拿到公钥,并检查其中的数据跟服务端之前给客户端的challenge是否相同,相同后会将公钥,id,与用户id对应保存起来。

验证Passkey

验证Passkey 使用Passkey进行身份验证,首先也是需要从服务端拿一些信息,如下:

{
  "challenge": "T1xCsnxM2DNL2KdK5CLa6fMhD7OBqho6syzInk_n-Uo",   //服务端生成防止被重现攻击,跟创建流程中的一样
  "allowCredentials": [], //允许的凭证,比如只允许当前设备之前创建的凭证
  "timeout": 1800000,
  "userVerification": "required",
  "rpId": "credential-manager-app-test.glitch.me"  //信任实体Id
}

客户端使用这个json来进行验证:

val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(requestJson = requestJson)
val getCredRequest = GetCredentialRequest(listOf(getPublicKeyCredentialOption))
coroutineScope.launch {
 try {
	 val result = credentialManager.getCredential(context = activityContext, request = getCredRequest)
	 handleSignIn(result)
 } catch (e: GetCredentialException) {
	 handleFailure(e)
 }
}

google play service的凭据提供者会找到与rpid匹配的凭据,并且弹窗让用户选择,如果我们设置了allowCredentials并且只有一条会直接弹出指纹或生物验证,成功后会返回类似如下信息给我们:

{
  "id": "KEDetxZcUfinhVi6Za5nZQ",
  "type": "public-key",
  "rawId": "KEDetxZcUfinhVi6Za5nZQ",
  "response": {
    "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiVDF4Q3NueE0yRE5MMktkSzVDTGE2Zk1oRDdPQnFobzZzeXpJbmtfbi1VbyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOk1MTHpEdll4UTRFS1R3QzZVNlpWVnJGUXRIOEdjVi0xZDQ0NEZLOUh2YUkiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZ29vZ2xlLmNyZWRlbnRpYWxtYW5hZ2VyLnNhbXBsZSJ9",
    "authenticatorData": "j5r_fLFhV-qdmGEwiukwD5E_5ama9g0hzXgN8thcFGQdAAAAAA",
    "signature": "MEUCIQCO1Cm4SA2xiG5FdKDHCJorueiS04wCsqHhiRDbbgITYAIgMKMFirgC2SSFmxrh7z9PzUqr0bK1HZ6Zn8vZVhETnyQ",
    "userHandle": "2HzoHm_hY0CjuEESY9tY6-3SdjmNHOoNqaPDcZGzsr0"
  }
}

回传以上信息给服务端,服务端会通过存储的公钥来验证signature,能验证则说明是匹配的用户,验证通过。

踩坑分享与总结

从上面的接入代码可以看到,google 的credentials libary已经帮我们把大部分的工作做掉了,我们更多的主要是去除了requestJson中的一些参数,客户端的代码还是比较简单的。当然也遇到很多的坑。 首先就是一定要保证服务端的返回json是要符合协议的,比如authenticatorSelection要按照格式来写,pubKeyCredParams最好把常见的支持的都加上,rp信息中的的name和id一定要有,id一定要用域名。

如果存在测试版本和线上版本包名不同,签名不同的情况,一定要分别设置好digital asset设置,如果用的是同一个域名,那么是可以在一个asset文件中设置多个app的。

因为google play services是该功能的基础,所以开发测试阶段使用的网络需要能够流畅的访问谷歌的服务。使用的测试机最好也是能够使用完整的google play services的。如果测试中出现类似下面的错误,可以去尝试升级google play services解决。

During create public key credential, fido registration failure: advy: Algorithm with COSE value -8 not supported

总体来说,如果是一个出海应用,并且对于应用的安全性有很高的要求,passkey是一个很好的解决方案。但是对于一个中国的应用来说,目前passkey还是不可用的,如果使用类似的公钥-私钥验证机制,那可以使用FIDO来实现。当然因为不是像google 和apple这样对于passkey支持这么好,实现起来会更加复杂,以后有机会可以再写一写。

参考资料

记解决MaterialButton背景颜色与设置值不同

2024年1月4日 22:02

最近的开发过程中,因为设计的风格采用了Android的Material风格,因此我们在项目开发过程中也使用了Android 的Material组件和主题,但是开发过程中法使用MaterialButton的时候,我们给按钮设置的背景颜色和实际展示的背景颜色不一样。网上搜索了一番也没找到原因,于是便开始查阅MateriButton的代码。

期望的背景实际的背景

经过一番研读终于找到原因,最终通过在style文件中添加如下设置解决。

<item name="elevationOverlayEnabled">false</item>

MaterialButton介绍

Google在Material库中给我们提供了MaterialButton组件,我们可以通过设置很多属性来设置它的样式,仅仅背景就可以设置它的边框,背景的圆角,背景的颜色,甚至可以自己设置背景的形状,除此之外还能设置文字样式,按钮上的图标等等。因为我们今天的主题是关于背景的问题的,这里我们仅仅介绍背景设置相关的东西。

正常情况下,对于一个Android的View我们可以通过设置setBackground() setBackgroundColor() setBackgroundResource()等方法来设置View的背景,而MaterialButton为了让我们能够直接修改颜色,设置圆角,则重写了setBackgroundColor()方法,实现如下:

public void setBackgroundColor(@ColorInt int color) {  
  if (isUsingOriginalBackground()) {  
    materialButtonHelper.setBackgroundColor(color);  
  } else {  
    // If default MaterialButton background has been overwritten, we will let View handle  
    // setting the background color.    super.setBackgroundColor(color);  
  }  
}

通过查阅代码,我们可以看到MaterialButton内部通过MaterialButtonHelper这个类来管理它的背景,如果我们没有通过setBackground给这个Button设置一个背景Drawable,MaterialButtonHelper会帮我们创建一个Drawable,当我们调用 setBackgroundColor的时候,实际上也会在MaterialButtonHelper内部处理,至于MaterialButtonHelper如何创建BackgroundDrawabale的流程,可以自行去看源码。

修改背景颜色的具体过程

上面说到的MaterialButtonHelper创建的背景Drawable就是一个MaterialShapeDrawable,前面的setBackgroundColor调用后实际上会调用到MaterialShapeDrawable的setTintList()方法来修改背景的颜色,实际上就是使用了Tint来修改我们的背景,在draw方法中我们可以看到如下的代码:

fillPaint.setColorFilter(tintFilter);

以上代码实现来背景颜色的修改。

在setTintList()的代码中和调用的函数中,我们发现了这样一行代码它修改了tintFilter这个变量。

tintFilter =  
    calculateTintFilter(  
        drawableState.tintList,  
        drawableState.tintMode,  
        fillPaint,  
        /* requiresElevationOverlay= */ true);

此处的tintList为我们刚刚设置的颜色,tintMode默认值是SRC_IN均不为空,该方法内部又调用了calculateTintColorTintFilter()方法。

到这里我们总结一下,setBackgroud是通过tint来修改了背景的颜色,tint的实现其实就是使用了Android画笔的颜色混合滤镜(PorterDuffColorFilter)来实现的。

背景颜色为什么与设置的不同?

private PorterDuffColorFilter calculateTintColorTintFilter(  
    @NonNull ColorStateList tintList,  
    @NonNull PorterDuff.Mode tintMode,  
    boolean requiresElevationOverlay) {  
  int tintColor = tintList.getColorForState(getState(), Color.TRANSPARENT);  
  if (requiresElevationOverlay) {  
    tintColor = compositeElevationOverlayIfNeeded(tintColor);  
  }  
  resolvedTintColor = tintColor;  
  return new PorterDuffColorFilter(tintColor, tintMode);  
}

以上是calculateTintColorTintFilter方法的代码,我们知道requiresElevationOverlay总是true,那就一定会执行到compositeElevationOverlayIfNeeded,那就说明这个方法内部把我们的颜色修改了,查看其实现,果然如此,代码如下:

protected int compositeElevationOverlayIfNeeded(@ColorInt int backgroundColor) {  
  float elevation = getZ() + getParentAbsoluteElevation();  
  return drawableState.elevationOverlayProvider != null  
      ? drawableState.elevationOverlayProvider.compositeOverlayIfNeeded(  
          backgroundColor, elevation)  
      : backgroundColor;  
}

翻阅代码我们可以看到drawableState是在Drawable创建的时候就创建了,而elevationOverlayProvider则是在MaterialButtonHelper中调用drawable的initializeElevationOverlay方法来初始化的,为ElevationOverlayProvider,而正是它的compsiteOverlayIfNeeded方法来变化了颜色。

修改颜色为我们设置的颜色

看到这里,首先想到是吧这个elevationOverlayProvider设置为null,那我们不就不会调用这个方法,颜色也就是我们最初设置的颜色了吗。然而,我们没法在MaterialButton中或者它的子类中去拿到Drawable的DrawableState,因此只能作罢。

再来继续看,ElevationOverlayProvider的compositeOverlayIfNeeded方法,它既然有个IfNeeded,那看来也不是一定会改变颜色了,继续看它的实现。

public int compositeOverlayIfNeeded(@ColorInt int backgroundColor, float elevation) {  
  if (elevationOverlayEnabled && isThemeSurfaceColor(backgroundColor)) {  
    return compositeOverlay(backgroundColor, elevation);  
  } else {  
    return backgroundColor;  
  }  
}

可以看到满足elevationOverlayEnabled且 backgroudColor和themSurfaceColor相同的情况下才会改变颜色,原来我设置的按钮颜色和主题中设置的colorSurface相同,此处我不可能去修改按钮颜色,我们只能去看看elevationOverlayEnabled能否修改,查看ElevationOverlayProvider的源码可以看到初始化的时候通过如下代码初始化了该值。

MaterialAttributes.resolveBoolean(context, R.attr.elevationOverlayEnabled, false)

看到这里,我们也就知道该如何解决我们的问题了,也就是在AppTheme或者当前Activity的Theme中修改elevationOverlayEnabled 为false。

除了Button之外,Material的其他一些组件也有同样使用这个属性来设置是否修改颜色的,遇到的时候也可以同样的方式解决。

与自我和解-读《被讨厌的勇气》

2023年4月13日 22:30

由于有了娃之后,对于小孩的管教很头大,先是看了《正面管教》这本书,书中作者的很多思想源于阿德勒的个体心理学,又看很多人推荐这本 《被讨厌的勇气》也便在微信读书将其读了。

整本书通过青年和哲人对话的方式,向我们讲述了阿德勒心理学 的内容,并且通过青年的问题开始,引导我们步步深入,最后得出人生很简单,不存在普遍性的人生意义,即使被讨厌自己的人讨厌,也可以自由地生活 。行文流畅,环环相扣,引得我很快就看完了。

决定我们自身的不是过去的经历,而是我们赋予经历的意义。这和弗洛伊德的主张相反 ,阿德勒反对使用过去的经历来解释当前的痛苦。我不敢说阿德勒的说法是否正确,但是这种方式,至少可以让自己从过去的经历中解脱,并且赋予自己生活新的意义。

我们应当尽量让自己脱离竞争的怪圈,这样自己眼中的世界会更加不同。例如,我自己之前有段时间听到扬声器中的声音,感觉很不好听,苦恼了很久,然后询问家人和朋友,他们表示其实并未关注我的声音是否好听,这些其实都是自己无意中在和别人比较竞争。

阿德勒心理的一个基本概念是,人的烦恼皆来自人际关系,有些人会讨厌自己,只是在通过自我厌弃来逃避人际关系。每个人都有自己的人生三大课题:交友、工作、爱,我们应当将自己的课题与其他人的课题分离开。比如对待儿童,我们应当将其当作一个与自己一样的一个人来真诚对待,这样可以减少其自认弱势的情绪。对于父母来说,孩子的人生也不是自己的人生,孩子的课题需要他们自己完成,父母也有自己的课题,应当避免失去自我。

对于孩子,阿德勒也并不是推崇放任,阿德勒心理学主张在了解孩子干什么的基础上对其加以守护。对于学习而言,告诉孩子这是他自己的事情,在他想学习的时候父母可以提供帮助,但是绝对不 妄加干涉,孩子没有求助的时候不指手划脚。伸伸手可以触及,但又不踏入对方领域,保持这样适度的距离很重要。只要这样,才能让孩子尽早的直面困难,学不会直面困难的孩子将会想要逃避一切困难。

跟正面管教书中的介绍一样,本书同样提到,对于孩子的教育,不可以批评也不可以表扬,并且分析了原因。表扬这种行为含有“有能力者对没有能力者所做的评价”这方面的特点,一个人表扬他人 的目的是”操纵比自己能力低的对方”。这种赏罚式的教育,对于孩子是操纵。对于孩子来说,会形成想要被别人表扬或想要去表扬别人,这种人际关系是不平等的,阿德勒称其为“纵向关系”,阿德勒心理学提倡平等的“横向关系”。自卑感就是纵向关系中产生的一种意识,如果能够对所有人都 建立起“虽不同但平等”的横向关系,就不会产生自卑情结。

不能表扬也不能批评,但是父母可以鼓励孩子。鼓励是帮助孩子用自己的力量去解决问题,需要他自己直面课题,也许要他自己下定解决问题的决心。这种情况下,双方是平等的横向关系。使用“谢谢”,对于帮助了自己的小孩或者同伴表示感谢,用“我很高兴”之类的话来传达自己真实的喜悦,也是基于横向关系的鼓励。这样做,可以让人感觉到自己有价值,从而获得勇气。

不将自己的孩子跟任何人相比,就把他当作他自己,对他的存在心怀喜悦与感激,不要按照理想形象去扣分。这样的话,平时就不会因为比别的孩子成绩差,比别的孩子淘气而烦恼了。这是所谓的不要用行为标准,而是用存在标准看待他人,不要用他人做了什么去判断,应对其存在本身表示喜悦和感谢。

同时,做人要有甘于平凡的勇气,这样对于世界的看法也会截然不同。对于自己来说 ,会减少与其他人的竞争。对于他人来说,更容易建立平等的横向 关系。接纳自己,诚实地接受做不到的自己,然后 尽量朝着能够做到 的方向努力,不对自己撒谎。

这些是对本书的一些个人总结和体会,以及部分借鉴。书的观点对于我来说很新颖,有助于从不同的角度思考人生,人际关系。下一步要继续去读一读阿德勒本书的经典书目,《阿德勒心理学》、《自卑与超越》、《理解人性》。

最后,以书中的一些句子来结尾。

人生的连续、是连续的刹那。人生很简单,并不是什么深刻的事情。如果认真过好了每一个刹那,就 没有什么必要令其过于深刻。人生中最大的谎言就是不活在“此时此刻”。起决定性的既不是明天也不是昨天,而是此时此刻。

防御型投资者的投资基础-读《聪明的投资者》

2023年3月21日 21:30

《聪明的投资者》这本书在微信读书的各个投资书单书单中都有推荐,在看有知有行的《投资第一课》中也多次提到这本书的内容。便找来花了一点时间读完了,读完之后觉得还是要写点东西方能将书本内容消化吸收。

我所读的是第四版的巴菲特注疏版,这本书于1949第一次出版,最后一版本即为1972年的第四版,巴菲特于2003年左右(未查到具体时间)进行注疏。书中虽然有些案列过时,一些市场的趋势有所改变,但仍然不失为一部经典。

巴菲特说,成功投资的关键是要有一个稳妥的知识体系作为决策基础,并且有能力控制自己的情绪,使其不会对这种体系造成侵蚀。这本书就是就是帮助读者构建一套自己的投资知识体系。

投资操作应该是以深入分析为基础,确保本金安全 ,并且获得适当的回报。不满足这些要求的操作就是投机。因此核心是: 深入分析,本金安全,适当的回报。同时如果想要投机操作,那么最好单独开立投机账号,并且在操作思想思路上两个账号都要完全独立开来。

作者把投资者分成两类,防御型(或者被动型)投资者和激进型(或进取型)。防御型投资者是关心资金安全同时又想花太多时间和精力的人,此类投资者的首要目的是避免重大错误或损失,其次是不必付出太多的努力、承受太大的烦恼去经常性地做出投资决策。相反,激进型的投资者则愿意付出大量的时间和精力去挑选更具吸引力的股票,以获取超出平均水平的回报。对于我们普通人来说,除了每日繁忙的工作以外还有家庭和社交,因此能够放在打理钱上的时间是非常有限的,所以大部分都还是属于防御型投资者。

投资是为了让自己的本金增值,存到银行本身就是增值,然而由于国内经济的飞速发展,各国银行不断的印钱,市场上的钱越来越多,导致持续的通货膨胀,紧靠银行存款很难跑赢通货膨胀。我们需要借助各种金融 工具来进行通知。作者建议防御型投资者同时投资和债券,并且投资于股票的资金不低于总金额的25%,但不得高于75%,同时剩下的金额投资于债券。在“熊市”股价低廉的时候,可以增加股票的投资比例,在市场价格上升到危险高度时,则应该将股票投资的比例减到50%一下。股票相比债券,可以在很大程度上上使投资者免受通货膨胀的损失,另一方面可以提供更高的多年平均回报。债券相比股票,波动比较小。对于能承受波动的年轻人,可以股票的比例高一点。债券也是有很多种,像国债,储蓄债,他们的风险较低,但同时又比储蓄的利息更高。而像企业债券,信用债,可转债等者风险要高一些,同时利息也会更高。

对于股票的购买,作者建议: 1. 适当但不过过度分散,应该持股10~30个之间。 2. 购买的公司应该是大型知名的 ,并且有稳健的财务。对于工业企业,股票的账面价值不低于总资本的一半,才算得上是 财务稳健的。 3. 每家公司都有长期支付股息的历史。 4. 应该将其买入的股票价格限制在一定的市盈率范围,参考每股收益,取过去七年的平均数,避免买的太贵。

但是通常单只股票通常都有购买限制,所以很多人的资金很难同时买到10个以上的股票。因此我们可以选择通过购买基金来间接的购买股票。在点评中,巴菲特推荐我们购买指数基金,此类基金管理费用低,同时他通常是跟踪某一市场指数,减少了基金经理人为操作的影响因素 。

投资是个人的事,应该建立在个人的独立思考和判断之上。关于投资顾问,作者认为聪明的投资者不会完全依赖金融公司提供的建议来从事买卖交易。金融服务公司的作用应当是提供建议和信息的。

最后一章,作者介绍了投资中心思想的“安全边际”,这应该是稳健投资的秘密。对于债券 ,可以通过比较企业的总价值和债务规模来计算,总价值高于债务的部分,是“缓冲价值”,对于投资者来说,在遭受亏损之前是有这些下降的空间的。同时,安全边际还能保证投资者不必对未来做 准确的预测。对于股票来说,当股价低于公司以财产和盈利为稳固基础发行的债券的价值时,可以认为有很大的安全边际。安全边际与分散化原则有着密切的逻辑联系。安全边际保证盈利的机会大于亏损的机会,分散购买保证总体亏损的可能性更小。 投资的意义不在于所赚的钱比一般人要多,而在于所赚的钱足以满足自己的需要。不确定性是投资领域最基本和无法摆脱的条件,通过学习来构建自己的知识体系就是降低不确定性,提高投资的成功率。

后记

这是离开学校之后的第一篇读书笔记,写下来是为了让自己对书的内容能够有所吸收,同时也是写作的锻炼。本文内容有不少从书中摘抄的,同时内容也有不少是个人观点,不构成投资建议。

这是一本好书,读了一遍,又画了一些笔记,写读书笔记的时候又翻了一下,还是很多没有理解,仍然需要有时间再重新来读一读。

新版Android Studio Logcat view使用简明教程

2023年2月23日 23:10

logcat-window.png

从Android Studio Dophin开始,Android Studio中的默认展示了新版的logcat。新版的logcat色彩上是更加的好看了,不同的tag会有不同的颜色,不同level等级的log默认也有不同的颜色。log过滤修改的更简洁了,当然使用起来也更加复杂了。原先的log视图只需要勾选就可以选择不同level的log了,只需要选择只展示当前应用的log就可以过滤掉其他应用的log了,但是新版只提供了一个输入框去过滤。在经过几个月的适应和对于官方文档的学习后,终于使用了,这里简单记录和分享一下。

定义自己专属的log view

log view 默认提供了两种视图,Standard View 和Compat View。Stand View会展示每一条log的日期,时间,进程线程id,tag,包名,log level以及message。Compat View只展示时间,log level和详细的message。可以通过log view左边的Configure Logcat Formatting Options按钮来修改,同时这个按钮中还有一个Modify Views选项可以来修改standard和 Compat视图的具体展示内容,可以定制自己的logview样式,如下图所示。

logcat-view-setting.jpg

个性化的logcat 视图不仅仅是可以自定义展示的内容,还可以修改log和filter的配色方案。前往Settings(Windows)/Preferences(Mac) ->Editor -> Color Scheme,选择Android Logcat即可修改log 的颜色,选择Logcat Filter即可修改filter的颜色。

以上修改的是logcat view的外表,我们还可以修改它的内核,一个是logcat循环滚动区的大小,以及新logcat window的默认filter,可以通过前往Settings(Windows)/Preferences(Mac) -> Tools -> Logcat 设置。

一些操作技巧

在标准布局下,或者我们的log太长的时候,一屏通常展示不下,我们需要不停的向右滑动,滚动才能看到log的信息,我们可以用log view左侧的Soft-Wrap logcat-soft-wrap.png按钮来让log换行。

左侧的Clear Logcat按钮可以清空logcat。左侧的Pause按钮可以暂停logcat的输出,方便看错误日志,可以避免关心的日志被新的日志冲掉。

新版本中,可以通过点击logcat tab右侧的New tab logcat-new-tab.png按钮来同时创建多个logcat view窗口。这种方式创建的不能同时展示,而利用logcat view左侧的split Panels 按钮则可以创建多个窗口,并且同时展示。每一个窗口都可以设置自己要展示的连接设备,展示样式,以及过滤选项。这样就可以很方便的同时观察多种log。

logcat-multi-window.jpg

通过键值对来过滤Log

logcat-query-suggestions.png

新的过滤器,看起来简单,实际上更加复杂且强大了。通过Ctrl+Space按键可以查看系统建议的一些查询列表。这里介绍一下查询中会用到的键: + tag: 匹配日志的tag字段 + package:匹配记录日志的软件包名,其中特殊值mine匹配当前打开项目对应的应用log。 + process:匹配记录日志的进程名 + message:匹配日志中我们自己填写的message的部分。 + level:与指定或者更高级别的日志匹配,比如debug或者error,输入level后as会自动提示可以选择。 + age:让窗口中只保留最近一段时间的log,值为数字加单位,s表示秒,m表示分钟,h表示小时,d表示天。如age:10s就只保留最近10s的日志。 + is: 这个键有两个固定的value取值,crash匹配应用崩溃日志,stacktrace匹配任意类似java堆栈轨迹的日志,这两个对于看crash查问题是非常好用的。

这么多的键匹配,是可以逻辑组合的。我们可以使用&|以及圆括号,系统会强制执行常规的运算符优先级。level:ERROR | tag:foo & package:mine 会被强转为level:ERROR | (tag:foo & package:mine )。如果我们没有填写逻辑运算符,查询语言会将多个具有相同键的非否定过滤视为OR,其他过滤视为AND。 如: tag:fa tag:ba package:mine 计算逻辑是 (tag:fa | tag:ba) & package:minetag:fa -tag:ba package:mine 计算逻辑是 tag:fa & -tag:ba & package:mine。这里的-用来表示否定,既tag不包含ba的情况。

新版的logcat view当然也是支持正则的,tag、message、package、process这几项是支持正则的。使用正则需要在键后面加一个~,例如: tag~:My.*Report。 除了正则这个选项之外,这几个键还有完全匹配和包含字符串即可的选项。不加修饰符号就是包含指定的字符串即可匹配。如果后面加=则要完全匹配才可以,例如process=:system_serverprocess:system_ser可以匹配到system_server的log,但是process=:system_ser则无法匹配到。

同时如上几个匹配选项都支持和前面说的否定符号连用如:-process=:system_server

既然新版支持了这么复杂和强大过滤功能,如果每次都现想现写,那肯定是头皮发麻。as也为我们提供了收藏和历史记录功能。点击右侧的的星星按钮即可收藏当前的过滤条件,点击左侧的漏斗即可查看历史和收藏,并且可以删除不想要的记录。

切换回旧版log view

最后的最后,如果你觉得新版本适应不了,还是想要切换回旧版本的log view,还想要保留新版的android studio,也还是可以通过修改设置进行切换的。 前往Settings(Windows)/Preferences(Mac) -> Experimental, 反选Enable new logcat tool window 即可,如下图所示。

disable_new_logview.jpg

学习工具的目的,是为了让工具更好的为我们服务。希望大家都能够通过使用as提供的新功能来提高效率,从而有更多的时间去风花雪月。

参考:https://developer.android.com/studio/debug/logcat

景德镇一日匆匆游

2023年2月4日 01:18

老婆家在皖赣交界的县,自驾只需要两个多小时就能到达景德镇,因此,很早就有想要自驾前往的想法,由于自己没有车因此一直没能成行。

今年过完年过来老婆家,一时兴起,决定租车前往。

作为驾驶员,一路上穿行在高速上,且经过很多的山和隧道,没什么机会拍照留下影像,主要是到达景德镇拍了一些照片。

恰逢周六,景德镇每周的乐天陶社创意集市在12点会收摊,我们首先驱车来到这里,人很多,各种摊位很多陶瓷很有意思,因此集市也没有留下什么照片。旁边的店铺里面有很多各种各样的陶瓷玩意,买了几个陶瓷玩具给小孩玩。

在旁边的一个不起眼的巷子中发现了一些师傅,有的在做模,有的在做坯子,甚至有些我也看不懂是什么步骤,但是陶瓷器具很多都要经过这些步骤吧。

随后便去了网上知名的寻味三宝吃饭,这家店所在的路两边都是山,如果有时间多多停留转转应该很不错。店内装修风格独特,但餐品就是比较常见了,点了几只烤乳鸽小家伙们倒是喜欢的很。

吃完饭,便前往御窑遗址博物馆,公园内的塔只能一楼看一下。遗址内可以看到明清时候的一些遗迹,博物馆的红砖建筑很漂亮,很多人在此处拍照。御窑博物馆内令人印象认可的是青花瓷特展,青花瓷真的非常漂亮,光线原因,没有能够拿得出手的照片。

博物馆的周围有很多古民居,但是都在进行修缮,相信下次再来的时候应该会很热闹了。旁边有一些非遗传承人,有人在售卖陶瓷,也有人在制作陶瓷,这些手工作品确实是工业机器很难制造出来的。

之后去了抚州弄小吃街,想象中的小吃街应该熙熙攘攘,然而到了之后发现街上冷冷清清。除了牛骨粉和油条麻糍,其他的也算不上特色了。买了两个油条麻糍便决定撤了。

最后去了中国陶瓷博物馆,其中看到了中国各个时代的陶瓷,从唐宋到现代,对于了解中国陶瓷的发展收获很多。另外还有一些特别展览,也很不错。由于时间原因,并未能全部看完。

由于总共花了五个小时左右的时间在路上,并且又带了三个娃,此次行程是非常紧凑,又非常匆忙的。博物馆的展都只是走马观花的看了一下,很多地方也没能够去,甚至也没能够去淘一套好用的茶具回来。

留有很多遗憾,希望下次有机会再回来好好看看。

面试官谈面试

2023年1月16日 23:30

 图: 明明 参加工作多年,找工作时参加过一些面试,经历过笔试,面试,电话面试等多种形式 。也作为面试官面试过很多人,也参加过公司的面试培训,观摩过其他同事的面试。最近系统学习了一下极客时间的《技术面试官识人手册》,课程介绍的东西虽然不能全盘拿来使用,但是还是有很多东西指的借鉴,今天想要从面试官的角度分享一下个人的学习体会以及个人对于面试的一些见解。

面试其实是一个公司与候选人进行双向交流的机会,也是双方进行双向选择的过程,公司通过面试官向候选人展示公司员工的风采以及介绍公司的业务技术等,候选人则是通过面试向面试官展示自己的技术素养,业务能力等。同时,面试的过程也是面试官和 候选人进行双向学习的机会。

公司和候选人双方都需要几轮面试过程中互相评估对方是否和自己匹配,公司需要确认候选人是否具有公司所需的技术能力(包括相关岗位必须的知识能力,软件编程能力,系统设计能力等),业务能力(对产品较好的理解能力,项目管理能力等),个人的综合软素质(学习能力,沟通能力,好奇心等)。

通常的招聘理念是招聘优秀的工程师而不仅仅是能干活的人,优秀的人常常是在他自己领域的技术知识是扎实的,能够把具体问题抽象成可解决的软件问题,并且能够使用软件工程的知识与技能去解决和实现他们。同时他有很好的代码设计实现能力和系统设计能力。在非技术层面 ,他能够有用很好的上面说到的一些软素质能力。

对于不同工作年限的人,面试的侧重点也会不同。对于刚毕业的学生或者工作一两年的新人,会更加关注他的成长潜力以及相关方面的软素质,比如会通过他以往的学习或者项目经历来考察他是否具有足够的学习能力,是否能够很好与人合作,用过的技术是否掌握扎实,有没有对于技术方面的热爱等等。对于一个经验丰富的老兵,通常会关注他的视野,以及他对于技术理解的深入,对于不同的团队来说,可能还会关注对于产品和团队的理解,软件系统的理解等。同时,不同的团队对于人的要求也是不一样的,有些团队也会寻找某些方面与团队比较互补的人选。

面试形式一般就是两人的对聊或者白板编程,想要对候选人进行评估 ,面试题的设计其实就很重要。好的面试题,应该是区分度、深度和覆盖范围都很好的。因此面试的过程当中,面试官可以根据候选人的表现来调整题目的难度,一是在候选人答不出来的时候给提示或者弱化要求来降低难度,二是可以通过追问和附加更多条件来增加难度,加大对于深度的延伸。

好的编程题或者系统设计题目,一般不会直接给一个抽象的问题(比如让候选人写出二叉树的前序遍历),而是一个实际问题。这样的问题,不仅仅可以考察编程能力,还可以对于实际问题的抽象能力以及需求分析的能力,同时面试官还可以观察候选人的沟通能力。对于这类问题,也便于面试官进行难度的调整。对于候选人,也应该多和面试官进行沟通,确认自己的理解是否正确,避免后续编程的实现完全错误。

对于软素质方面的考察 ,一般会通过面试的过程中进行考察,比如通过编程环节考察沟通能力 ,需求分析能力。以及会通过与候选人聊过往项目和经历来考察,因为一个人过往环境中解决困难问题时候所采取的行为在相当程度上决定了他未来会 怎样应对类似的问题。

好的面试官会有很好的面试礼节,在面试开始会握手问好,帮助候选人化解紧张气氛,进入到面试中。面试结束也会留给对方问问题的机会,并对于候选人表示感谢等。

最后再说一下,公司的面试通常不是为了把候选人考倒,而是发现对方的亮点和长处,能够为自己找到合适的人才。

2023年的第一篇文章,是个人写作能力的锻炼,也是输出的尝试,毕竟只有能够输出才算对所学内容有所消化。

2022年个人总结

2023年1月3日 21:30

向上生长 图: 明明 已经有几个年头没有写过年终总结了。 2022年是非凡的一年,看到很多人写了年终总结,忍不住也来写一写。 这一年如果使用几个关键词来总结,我想我的关键词是魔幻,起伏和充实。

魔幻

2022年已经是疫情的第三年了,反而过得比疫情的第一年更加的艰难。这一年,我们经历了两个月的全城封闭,大规模的参与团购。这一年我们开始每天做核酸,没有核酸你就寸步难行。在解封之后,因为次密接提级,被拉到了方舱隔离了一周,没有网络,使用自己的手机流量联网办公。在这一年即将结束时,我们得以全民放开管制,由于政策的突变,大量的人感染,并且医疗和药品准备不足,很多人买不到要,或者无法就医。当然了,在这一年的年尾,我也全家感染新冠,所幸大家都康复了,为这一年画上了完美的句号。疫情之魔幻,难以捉摸。

起伏

一方面,起伏是 工作上的起伏。三月封闭前几天,公司领导宣布了公司运行出现了问题,团队即将解散。公司从去年下半年开始各方面情况就不太好,过完年回来之后其实公司在产品迭代,和运行上就没有什么动作了。公司同事们这段时间也都是摸鱼的状态,这个消息对所有人来说都是非常突然。几天之后,大家就都被关在家里了,也就只好各自准备开始面试。我们这样一个小的创业团队,也即就此解散,由于疫情原因很多人都没能在见面告别。 之后一段时间便是紧张的复习准备面试。对于我在今年找工作真的是非常困难,一方面是整体大环境不好,很多公司缩减招聘名额,另一方面是由于前前公司的竞业限制仍未到期,很多的互联网公司都不能投递。经过一个多月的努力,终于找到了一份满意的工作,具体公司不便透露。相比与之前几份工作,新公司是全新的行业,很多行业知识都不了解。之后的一段时间便是开始在新公司熟悉业务,熟悉同事。同样由于疫情原因,到了八月份才 得以去导板公司与同事们进行交流。

另一方面是个人心态和情绪的起伏。在年初回来工作初期的阶段,是比较忐忑的,知道公司状况不太好,担心可能某天会面临公司破产,同时又希望这一天不会到来。在被告知团队解散后,一是惋惜团队最终还是创业失败了,另外也比较担心自己的前途。找工作期间,则是比较焦虑,一方面市场不好,二是许久都没有参加过什么面试,另外比较担心自己和更加年轻的工程师相比是否竞争力不足。在此,要感谢新公司同事在面试和工作过程中对我的认可和支持。入职新公司之后,心态上面调整了很多,但是心有余悸,仍觉得需要未雨绸缪,所以还是花了时间充实自己。

充实

平心而说,从四月算起的这一年,还是特别的充实的。 首先,疫情封闭起就报名了英语培训课程,这一次没有半途而废,坚持了下来,完成了最多100多天的每日学习签到。到目前为止,虽然英语还不是很好,但是已经能够借助google meeting的实时字幕功能,与外国人进行交流,并且比较顺利的与几位海外候选人进行英文面试,与海外同事进行需求沟通。 另外今年耐心看了很多不错的好书,即使解封后每天有很多工作要做,睡前也会抽一点时间进行阅读。记忆犹新的好书有邓小平时代,周恩来传,置身事内,正面管教等。伟人对于个人的工作其实没有什么用,但是通过他们的经历他们所作的决策令人敬佩,鼓舞自我。置身事内这本书,让我对于中国当前的经济政策有更详细的了解,知道了一些政策的制定的原因,比如中国的分税制,城市的土地政策等,也让身在国内的我们对于国内经济的走势有了一点点的理解。 最后就是,在8月份开始,重新开始去锻炼身体,并且今年坚持的还不错,每周给自己定下一些简单的训练计划。多年以前开始健身,中间一次又一次的开始之后又是放弃。这一次希望能够坚持下去,打造更加健康的身体,同时也能够在体型上有所改善。

总结

以上就是2022年的大体情况,对于个人来说,其实这一年也还不错,但是焦虑依旧在。新的一年,打算立个Flag,尝试进行一些输出,让这个荒废已久的博客增加一点生机。在过去一年,虽然有比较多的输入,读书或者看一些专栏之类的,但是却没有输出,看的书基本上都是泛读,知识的消化还是很少。新的一年,可以写一些读书笔记,将个人的输入转化输出,提高自我的写作和表达能力。 新的一年要多与朋友在理财,个人学习,读书等方面进行交流,如果有可能去认识更多的朋友,也欢迎读者与我交流。当前在做的一些事,比如健身,英语学习等,仍然要持续的坚持下去。

2022年在MacOs上编译AOSP

2022年5月17日 22:30

之前苦于电脑磁盘空间比较小,而android系统的源码越来越大,一直没有机会自己编译Android系统。这次换了电脑,磁盘足够大,可以尝试一下了。 而android源码的网站红色的字写着 Platform development on MacOS isn’t supported as of June 22, 2021. ,我就知道不会那么容易了。

我的电脑环境:

2021款 M1芯片 Macbook Pro 16GB运行内存 MacOS Monterey(12.1)

环境准备

安装xcode和相关工具

  • 从appstore安装Xcode
  • 安装xcode command line tools:

$ xcode-select –install

  • 安装Rosetta(M1芯片需要,x86芯片不需要)

$ softwareupdate –install-rosetta

创建大小写敏感的磁盘映像

我们先创建个350GB的大小

$ hdiutil create -type SPARSE -fs ‘Case-sensitive Journaled HFS+’ -size 350g ~/forest.dmg

设置环境变量

我本地用的zsh,直接在.zsh_env中写,并配置挂载映像的方法

#  设置最大打开文件数量,防止编译过程中因为打开文件数量太多失败
ulimit -S -n 2048
# 编译缓存
export USE_CCACHE=1
# 挂载映像
function mountForest { hdiutil attach ~/forest.dmg.sparseimage -mountpoint /Volumes/Forest; }
#卸下挂载
function umountForest() { hdiutil detach /Volumes/Forest; }
export PATH="/opt/local/bin:/opt/local/sbin:$PATH"
export PATH=~/.bin:$PATH

编辑完保存之后,执行一下如下语句使配置当前就能生效 source ~/.zshenv

下载源码

$ mkdir ~/.bin
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.bin/repo #下载repo
$ chmod a+x ~/.bin/repo #设置repo权限
$ mountForest #挂载映像
$ cd /Volumes/Forest
$ mkdir aosp_mata
$ cd aosp_mata
$ git config --global user.name "Your Name"
$ git config --global user.email "you@example.com" 

$ repo init -u https://android.googlesource.com/platform/manifest -b android-11.0.0_r48 #可自选版本,我这用的是11.0.0的最后一个tag
$ repo sync

之后便是无尽的等待去下载源码,国内的网络下载不了,自己想办法爬墙吧。

开始编译

如果没有问题,在源码目录直接执行以下命令就可以编译了

$ source build/envsetup.sh
$ lunch aosp_arm-eng
$ make -j4

lunch后面的参数也可以不填,则会显示出来所有可以的选项,自己选一个进行设置就行。 make就开始编译, -jN用于设置任务数, N应该介于计算机上的CPU线程数的1-2倍之间为宜,我的M1 MAC 是10核,就先设置了24。

理论上这样就可以慢慢的等就能编译成功了,然而,如果可以这么简单就不需要我写一篇文章了,直接看android官方文档就行了。为了节省时间,先把下面的问题改改再编译。

问题解决

问题一:Could not find a supported mac sdk

大概是这样的log

[ 94% 171/181] test android/soong/cc
FAILED: out/soong/.bootstrap/soong-cc/test/test.passed
out/soong/.bootstrap/bin/gotestrunner -p ./build/soong/cc -f out/soong/.bootstrap/soong-cc/test/test.passed 
-- out/soong/.bootstrap/soong-cc/test/test -test.short
--- FAIL: TestDefaults (10.86s)
    cc_test.go:3075: "Could not find a supported mac sdk: [\"10.10\" \"10.11\" \"10.12\" \"10.13\" \"10.14\" \"10.15\"]"
    cc_test.go:3075: "Could not find a supported mac sdk: [\"10.10\" \"10.11\" \"10.12\" \"10.13\" \"10.14\" \"10.15\"]"
    cc_test.go:3075: "Could not find a supported mac sdk: [\"10.10\" \"10.11\" \"10.12\" \"10.13\" \"10.14\" \"10.15\"]"
    cc_test.go:3075: "Could not find a supported mac sdk: [\"10.10\" \"10.11\" \"10.12\" \"10.13\" \"10.14\" \"10.15\"]"
    cc_test.go:3075: "Could not find a supported mac sdk: [\"10.10\" \"10.11\" \"10.12\" \"10.13\" \"10.14\" \"10.15\"]"
    cc_test.go:3075: "Could not find a supported mac sdk: [\"10.10\" \"10.11\" \"10.12\" \"10.13\" \"10.14\" \"10.15\"]"
--- FAIL: TestDoubleLoadbleDep (0.05s)
    cc_test.go:733: "Could not find a supported mac sdk: [\"10.10\" \"10.11\" \"10.12\" \"10.13\" \"10.14\" \"10.15\"]"
..... ....

原因是指不到指定的mac sdk 可以看一下/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs文件下有没有 MacOSX12.3.sdk , 然后在然后在 /build/soong/cc/config/x86_darwin_host.go 文件中找到 “darwinSupportedSdkVersions“ 添加 MacOSX12.3.sdk 对应的版本号——12.3,如果你的macosx的sdk是别的就填别的。

darwinSupportedSdkVersions = []string{
		"10.10",
		"10.11",
		"10.12",
		"10.13",
		"10.14",
		"10.15",
		"12.3",
}

另外你也可以到https://github.com/phracker/MacOSX-SDKs/releases 去下载10.15的sdk放到上面的文件夹里面。

问题二: v8引擎无法编译,一些文件找不到

由于2021年后,官方不维护mac上的开发环境了,所以external/v8下面有很多编译错误,这里直接采用回滚代码的方式,我是回滚到了 Upgrade V8 to 8.8.278.14 提交的前一个Commit

cd external/v8
git checkout 9304fbb

问题三: undeclared identifier ‘PAGE_SIZE’

system/core/base/cmsg.cpp:36:21: error: use of undeclared identifier 'PAGE_SIZE'
  if (cmsg_space >= PAGE_SIZE) {
                    ^
system/core/base/cmsg.cpp:78:21: error: use of undeclared identifier 'PAGE_SIZE'
  if (cmsg_space >= PAGE_SIZE) {
                    ^

看起来是PAGE_SIZE这个常量没定义,那就去补上呗。去 system/core/base/cmsg.cpp 文件开头添加 PAGE_SIZE 的声明

#ifndef PAGE_SIZE
#define PAGE_SIZE (size_t)(sysconf(_SC_PAGESIZE))
#endif

问题四: incompatible pointer types passing ‘unsigned long *’ to parameter of type ‘uint32_t *‘

external/python/cpython2/Modules/getpath.c:414:50: error: incompatible pointer types passing 'unsigned long *' to parameter of type 'uint32_t *' (aka 'unsigned int *') [-Werror,-Wincompatible-pointer-types]
else if(0 == _NSGetExecutablePath(progpath, &nsexeclength) && progpath[0] == SEP)

external/python/cpython2/Modules/getpath.c 中:

#ifdef __APPLE__
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
    uint32_t nsexeclength = MAXPATHLEN;
#else
    unsigned long nsexeclength = MAXPATHLEN;
#endif
#endif

改成:

#ifdef __APPLE__
    uint32_t nsexeclength = MAXPATHLEN;
#endif

external/python/cpython3/Modules/getpath.c 中的:

#ifdef __APPLE__
char execpath[MAXPATHLEN + 1];
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
    uint32_t nsexeclength = Py_ARRAY_LENGTH(execpath) - 1;
#else
    unsigned long  nsexeclength = Py_ARRAY_LENGTH(execpath) - 1;
#endif
#endif

改成:

#ifdef __APPLE__
char execpath[MAXPATHLEN + 1];
uint32_t nsexeclength = Py_ARRAY_LENGTH(execpath) - 1;
#endif

以上问题改完应该就可以编译成功了,如果是在后面java编译阶段失败,可以先试试重新执行make试试,如果还是不行的话就上网找解决方案吧。

编译idegen模块导入Android Studio

使用如下命令编译idegen模块:

mmm development/tools/idegen/

完成之后,执行如下命令:

development/tools/idegen/idegen.sh

之后就会在根目录生成对应的 android.iprandroid.iml IEDA工程配置文件,之后在IDEA或者Android Studio中打开android.ipr就能浏览源码了。

参考

参考了以下资料和网友的分享,非常感谢:

❌
❌