admin 发布的文章

XDA论坛上看了1很久,Android 11就只有crDroid有官方支持。加上Resurrection Remix OS用得真不爽,主要是自动杀进程,而且不分前后台。于是五一假期狠下心刷上crDroid,用了一段时间,很爽!流畅、不杀进程、支持国产支付app的指纹,续航还行。

注:目前此ROM处于无人维护状态!

1. 相关下载

1.1 crDroid ROM
官网不仅可以下载ROM,还提供小米官方固件(欧版MIUI)、Recovery、OpenGapps等的链接:
https://crdroid.net/picasso

1.2 欧版MIUI
目前最新版是12.1.8,据说今年6月会推出12.5适配。当然,这不是重点。下载地址:
xiaomi.eu_multi_HMK305G_V12.1.8.0.RGICNXM_v12-11.zip
https://sourceforge.net/projects/xiaomi-eu-multilang-miui-roms/files/xiaomi.eu/MIUI-STABLE-RELEASES/MIUIv12/

1.3 Recovery
crDroid推荐的Recovery是OrangeFox。界面跟Twrp非常不同,感觉更像是文件管理器,但功能还是一样。
OrangeFox-picasso-stable@R11.1_1.7.zip
https://orangefox.download/zh-CN/device/picasso

1.4 Margisk
目前几乎是获取root权限的唯一方案。下载地址:
https://github.com/topjohnwu/Magisk/releases

要注意,从Margisk 22开始,root安装包和root管理工具,都合并为一个apk文件。root系统时,只需用Recovery刷入该apk文件。

1.5 Gapps
由于OpenGapps的Android 11版还没正式发布(当前处于测试),所以我选用NikGApps。下载链接:
https://nikgapps.com/downloads.html#downloads

一般选在Core版就可以了。值得注意的是,如果要开启Google Assistant(Google助手),需要把Google Velvet(即Google搜索)安装为系统App。NikGApps提供了对应的Addons(文件名为:NikGapps-Addon-11-Velvet-signed.zip),可以通过Recovery直接刷入系统。

2. 刷机过程

2.1 解锁及刷Recovery
都是常识性操作。刷Recovery后,最好先备份当前系统。

2.2 备份数据
钛备份不再更新了,推荐使用OAndBackupX备份App及数据。可通过F-Droid安装:
https://f-droid.org/en/packages/com.machiav3lli.backup/

还有联系人和短信的备份,不再赘述。

2.3 刷机步骤
按刷机顺序排列,crDroid的方案是:OrangeFox -> 欧版MIUI -> crDroid -> Margisk -> OpenGapps。我的方案只是用NikGApps替换OpenGapps。另外,最好先“双清”再开刷。

3. 初始设置

3.1 去掉WiFi和信号出现“x”符号
需要使用adb执行以下命令:

adb shell settings put global captive_portal_mode 0
adb shell settings put global captive_portal_https_url https://www.google.cn/generate_204

命令执行成功后,手机开启飞行模式,然后关闭飞行模式,即可解决。
参考:https://www.uso.cn/post/view/47990

3.2 开启Google Assistant(可选)
初次进入系统后,不插入SIM卡,语言选English(US)。安装Google Assistant并设置开启。成功后,再插入SIM卡,并设语言为中文。

Eclipse虽老,但仍然好用,特别是对于老Java码农来说。

1. 版本选择

一般Java的Web开发,选择Eclipse IDE for Enterprise Java and Web Developers。官方下载链接如下:
https://www.eclipse.org/downloads/packages/

2. 实用的初始化设置

1)修改默认字符集为UTF-8

windows -> Preferences -> General -> Workspace -> Text file encoding -> 选UTF-8

2)修改默认字体,改善中文显示太小

windows -> Preferences -> General -> Appearance -> Colors and Fonts -> Basic -> Text Font -> Edit -> 选Courier New

3)代码自动提示功能失效的解决方法

Window -> Preferences -> Java -> Editor -> Content Assist -> Advanced -> Select the proposal kinds contained in the 'default' content assist list -> 勾选"Java Non-Type Proposals"、"Java Proposals"、"Java Type Proposals"三个选项

4)在输错方法后仍然出现代码自动提示

Window -> Preferences -> Java -> Editor -> Content Assist -> Auto Activation triggers for java -> 改为.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

5)禁用Language Servers,提高Eclipse性能

Window -> Preferences -> Language Servers -> 取消所有勾选

6)安装插件Quick Bookmarks plugin,快速的标记和访问书签

  • 安装:Help -> Eclipse Marketplace -> 搜“Quick Bookmarks plugin”并安装
  • 使用:Alt+[数字],标记书签。Alt+Shift+[数字],跳转到书签。

工作上遇到需要在浏览器展示PDF文件,于是找到了Mozilla开发的PDF.js。玩了一下,结论是,直接使用其自带的示例是简单的方法。

PDF.js的官网:https://mozilla.github.io/pdf.js/
github项目页面:https://github.com/mozilla/pdf.js

主要是没找到有用的开发文档,而自己也不会Node.js的开发。所以尝试自己写的页面,只能利用HTML 5的canvas展示PDF内容。官方自带的示例,会把PDF转换成HTML,并且有显示目录、缩略图、打印、等各种实用的功能,媲美很多完整的PDF阅读软件。

这里记下写过的页面,可以翻页、放大缩小:

<h4>显示PDF</h4>
<p>
    <button id="prePage">上一页</button> <input type="text" id="curPage" value="" readonly /> <button id="nextPage">下一页</button>
    <br />
    <button id="zoomIn">+</button> <input type="text" id="zoomScale" value="1" readonly /> <button id="zoomOut">-</button>
</p>
<p>
    <canvas id="the-canvas" style="border: 1px solid black; direction: ltr;"></canvas>
</p>

<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="/js/pdfjs/pdf.js"></script>
<script>
//加载PDF按钮
pdfjsLib.GlobalWorkerOptions.workerSrc = '/js/pdfjs/pdf.worker.js';//自己的路径

var loadingTask = pdfjsLib.getDocument('/pdfjs/docker.pdf'); 
var pdfDoc = null;
var totalpage = 0;
var curPage = $("#curPage");
var zoomScale = $("#zoomScale");

loadingTask.promise.then(function (pdf) {
    //加载指定界面(第一页)
    pdfDoc = pdf;
    totalpage = pdfDoc.numPages;
    getPage(1);
});

function getPage(pageNum) {
    if(pageNum < 1) {
        pageNum = 1;
    } else if(pageNum > totalpage) {
        pageNum = totalpage;
    }
    setCurPageNum(pageNum);
    pdfDoc.getPage(pageNum).then(function (page) {
        //var scale = 1;
        var viewport = page.getViewport({ scale: getZoomScale() });
        var canvas = document.getElementById('the-canvas');
        var context = canvas.getContext('2d');
        canvas.height = viewport.height;
        canvas.width = viewport.width;
        var renderContext = {
            canvasContext: context,
            viewport: viewport,
        };
        page.render(renderContext);
    });
}

function makeThumb(page) {
    // draw page to fit into 96x96 canvas
    var vp = page.getViewport(1);
    var canvas = document.createElement("canvas");
    canvas.width = canvas.height = 96;
    var scale = Math.min(canvas.width / vp.width, canvas.height / vp.height);
    return page.render({canvasContext: canvas.getContext("2d"), viewport: page.getViewport(scale)}).promise.then(function () {
        return canvas;
    });
}

function loadThumb() {
    var pages = []; while (pages.length < pdfDoc.numPages) pages.push(pages.length + 1);
    return Promise.all(pages.map(function (num) {
        // create a div for each page and build a small canvas for it
        var div = document.createElement("div");
        document.body.appendChild(div);
        return pdfDoc.getPage(num).then(makeThumb).then(function (canvas) {
            div.appendChild(canvas);
        });
    }));
}

function getCurPageNum() {
    return parseInt(curPage.val());
}
function setCurPageNum(pageNum) {
    return curPage.val(pageNum);
}
function getZoomScale() {
    return parseFloat(zoomScale.val());
}
function setZoomScale(scale) {
    return zoomScale.val(scale);
}
$("#prePage").click(function(){
    var pageNum = getCurPageNum() - 1;
    getPage(pageNum);
})
$("#nextPage").click(function(){
    var pageNum = getCurPageNum() + 1;
    getPage(pageNum);
})
$("#zoomIn").click(function(){
    var scale = getZoomScale();
    scale = Math.round((scale + 0.2) * 100) / 100;
    scale > 2 && (scale = 2);
    setZoomScale(scale);
    getPage(getCurPageNum());
})
$("#zoomOut").click(function(){
    var scale = getZoomScale();
    scale = Math.round((scale - 0.2) * 100) / 100;
    scale < 0.6 && (scale = 0.6);
    setZoomScale(scale);
    getPage(getCurPageNum());
})
</script>

最近接触了两款开源、跨平台、支持多种SQL数据库的数据库管理工具,值得记录一下。

DBeaver
官网:https://dbeaver.io/
2020年疫情期间,在家办公,想找个数据库管理工具,可以在Linux上访问SQL Server数据库,于是遇到DBeaver。界面像Eclipse,容易上手;基于Java,可以跨平台使用;使用JDBC,几乎支持所有数据库。在Linux上,几乎是万能的数据库管理工具了。

HeidiSQL
官网:https://www.heidisql.com/
在Windows上安装MariaDB 10.4.12时,发现自带了HeidiSQL数据库管理工具。界面及操作都跟MySQL Workbench相似,清晰明了,而且支持各种SQL数据。比较意外的是,其基于Delphi开发,所以Linux上需要利用Wine运行。

顺德双皮奶,作为代表家乡的特色甜品小吃,一直深受本人喜爱,只是会吃不会做。近来几乎每天都买水牛奶给孩子补充营养,于是尝试做一下,原来也很简单。主要是以前错误以为第一层奶皮需要技巧弄上去,实际是物理原理,脂肪会浮在水面上。所以,只要弄到水牛奶,再简单弄一下就能吃到双皮奶了。

材料(两碗份量):

  • 水牛奶:250g
  • 蛋清:50g(大概一只鸡蛋的蛋清)
  • 糖:12g(可根据口味增减)

做法:

  • 1,水牛奶煮开,平均倒入两个碗内。放凉,让第一层奶皮形成。
  • 2,轻轻拨开奶皮,倒出牛奶,并让奶皮留在碗里。
  • 3,鸡蛋分离出蛋清和蛋黄。倒出的牛奶,加入蛋清和糖,搅拌均匀至混合。
  • 4,牛奶和蛋清混合物,用筛网过滤一下(去除杂质,让口感更滑),再平均倒回两个碗里。
  • 5,碗上盖上小碟子(或者保鲜膜、锡纸之类,还是小碟子比较环保)。待蒸锅水沸后,放上去蒸7到10分钟(我是8分钟)。
  • 6,蒸好后,放凉到接近体温再食用。夏天可以放冰箱冷藏后食用。

Google Camera(简称gcam)自推出以来,一直是最喜爱的摄影应用(可惜后来变成Pixel机型专属应用)。幸好有开发者移植到其它机型,特别是像红米Note 4X那种渣拍照的手机,极大提升了拍照能力。近来在红米K30 5G上也装上了gcam,并默认开启了“动态照片(Motion Photo)”功能。本来没啥影响,只是拍出来一堆文件名以MVIMG开头或者扩展名前带有“.MP”的照片,昨天好奇研究了一下,才发现就是动态照片。

动态照片,简单来说,就是把拍照前几秒录下视频,并把视频与拍出来的照片整合在一起,生成一个jpg文件。目前发现两种格式:文件名后面带有“.MP”的,在EXIF信息里会说明mp4文件在整个jpg文件中位置;文件名以“MVIMG_”开头的,jpg文件里有个“ftypmp4”标识,该标识后面的数据就是mp4文件。

其实动态照片也没什么坏处,但是找了一圈也找不到可以直接浏览动态图片的Android应用。如果是看不到的视频,那保存在照片中,有什么意义?还浪费了存储空间,也不利于分享、传输。最后找了个工具,叫GoMoPho,把所有拍摄的动态照片都转为普通jpg文件。其实就是把动态文件切割为jpg和mp4两个文件,我保留了jpg并删除了mp4。GoMoPho的相关网址如下:

Google motion photos video extractor.
https://github.com/cliveontoast/GoMoPho

GoMoPho虽然只有命令界面,但是支持上面提到的两种动态照片,而且已移植到多种操作系统,还能支持批量处理文件夹的文件。

这是个简易葡挞食谱。网上的视频看到的,简易的地方是,利用比葡挞皮更容易买到的手抓饼来做。试着做了一下,并修改了材料份量,效果还不错。

1. 材料(做6个的份量)

  • 原味手抓饼 1块
  • 鸡蛋 1个
  • 牛奶 80克
  • 白糖 15克

2. 做法

  • 1)制作挞皮。手抓饼解冻,卷起来,平均切成6份。搓圆,摊在蛋挞模具上,做成碗状。
  • 2)制作挞液。鸡蛋打散,加入牛奶和白糖,搅拌至白糖融化。然后过筛,去除杂质,带来更细滑的口感。
  • 3)挞皮倒入挞液,8分满即可。挞液会在烤的时候涨起,太满会溢出,导致挞皮容易糊。
  • 4)烤箱预热10分钟,200摄氏度中层烤20分钟。挞皮金黄,挞液有焦糖色,即可出炉。

3. 总结

  • 1)鸡蛋尽量选小的,如果是比较大的鸡蛋,要减少牛奶的份量。
  • 2)手抓饼一定要选原味的。毕竟没人想吃带葱的葡挞吧。
  • 3)出炉后,要放凉一下才能吃。主要是怕烫嘴(笑)。

今天烧烤时,顺便烤了板栗,非常成功!记录一下经验吧。

1. 材料

  • 小板栗 120g左右(一人一次的份量)

2. 做法1

  • 1)小板栗洗干净,用刀切个开口,大概二分之一周长。一般用刀砍下去,板栗没有分成两半,而是粘在刀上,就可以了。砍板栗的教程,具体可以参考李子柒于2020-10-10发布关于中秋节的视频,在12:46处(笑)。
  • 2)开水里煮10分钟。
  • 3)从水中捞出放烤盘里,烤箱预热后,以190摄氏度烤10分钟。注意不要烤糊,烤到板栗外壳干脆即可,这样更容易剥开。
  • 4)这个做法,可以用微波炉代替烤箱。但是板栗处理不好的话,容易爆炸(喷得微波炉内壁到处都是板栗碎),不推荐。

3. 做法2

  • 1)小板栗洗干净,用锡纸包好。用竹签戳一个小洞,用于排气。
  • 2)放在碳炉(烧烤炉)上,大概烤半个小时到1个小时。
  • 3)由于锡纸把板栗里的水分都锁住,所以做出来不会变得太硬,非常好吃。

4. 注意

  • 1)选用个头小的小板栗,是因为更容易熟,做起来少费点时间。
  • 2)板栗一次不能多吃。其淀粉含量比较高,多吃容易导致消化不良(例如放屁量增多)。

作为MIUI恐惧者,无奈LineageOS官方没有支持这台红米K30 5G,只能诚惶诚恐地使用欧版MIUI。直到某天发现了Resurrection Remix OS官方支持这款手机,才终于脱离MIUI。

查了资料,才知道Resurrection Remix OS是基于LineageOS的一款开源ROM,基本体验与LineageOS一致,并增加了很多设置(基本上是界面的,个人感觉用途不大),适合喜欢原生Android的用户。

LineageOS的优点基本继承了,总结一下缺点吧:

  • 1)国内支付应用,基本不能使用指纹支付。历史原因,一直遗留下来的问题。跟LineageOS一样。
  • 2)关屏后不能双击屏幕打开锁屏界面
  • 3)不能双击桌面锁屏。可以设置双击任务栏或者三大金刚键进行锁屏。
  • 4)不能拍摄6400万像素的照片。ROM自带相机和Google Camera移植版,最高都只支持1610万像素。不过即使是MIUI的自带相机,拍出来的6400万像素照片基本直出(纯粹自我安慰)。
  • 5)刚开始使用,比较耗电。做了一些优化后,后面变得相对省电一点。不过,这手机本身也不怎么省电。
  • 6)长时间使用的应用,容易自动退出。比如Chrome开个视频后,很大几率会自动关掉并回到桌面。可能是电源管理自动优化吧。

总的来讲,曾经的LineageOS用户可以放心刷,也没有遇到影响日常使用的bug 。

刷机过程,跟LineageOS一样。重点还是那句:刷机前先备份好数据。Recovery备份分区(刷机失败时可以还原系统) + Ti Backup备份应用(用于迁移应用及数据)。

1. 下载相关数据

2. 刷机

  • 备份数据。最好连sdcard的数据也备份一下
  • wipe手机,即Recovery格式化data分区
  • 解锁、刷recovery
  • 刷ROM
  • Recovery里Root系统
  • 刷Opengapps
  • 清cache
  • 重启进入系统

要注意,进入系统后,需要连Google验证。

3. 耗电优化的处理。当前的节电设置如下:

  • a)屏幕刷新率设为 60Hz,在“设置”->“系统”->Device-specific settings->Minimum Refresh Rate。120Hz屏幕其实很丝滑,但60Hz确实够用。
  • b)关闭 5G 网络,只用 4G 。设置移动网络的首选网络类型为“LTE/WCDMA”。当前来说,5G除了耗电比较快,没感受到什么优势。
  • c)限制应用使用电量。在电池管理器设置受限应用。目前设了 Google Play 商店。
  • d)关闭 Google 账户的自动同步功能,只开启了 Chrome 和 Gmail 。
  • e)冻结了一些不常用但不可缺的应用。冰箱、Shelter 、island 等。其中 island 的名称太中二,个人接受不了而放弃。用 Shelter 的话,如果工作空间的应用没用到 GMS,最好冻结它,并尽量安装非无依赖 GMS 的应用。

动画《放学后海堤日记》第10集,提到吃不完的竹荚鱼做成一夜干,不仅很好吃,还能提高存储时间。对这个做法很好奇,于是周末试了下,果然很惊艳!

虽然一夜干可以用新鲜鱼和冰鲜鱼,但是为了避免失败而造成的浪费,选用了太阳鱼(无细骨的淡水鱼)。最后烤制时,用了烤箱代替炭炉。

材料:

  • 太阳鱼 1条
  • 清水 500ml
  • 盐 50g

做法:

  • 1,太阳鱼削鳞,从背部开刀,去鳃、清理内脏、清理黑膜,清洗干净。
  • 2,清水和盐配成10%浓度的盐水,放入鱼,浸泡30分钟到1小时。盐水放入适当的米酒,可以去腥。
  • 3,从盐水取出鱼,用厨房纸吸干表面水份,放入冰箱过夜。
  • 4,从冰箱取出鱼,再次吸干表面水份。烤箱最高温度(我的是230°C)预热10分钟后,把鱼放最上层,烤大约20分钟,烤至表面金黄即可。烤的过程要适时翻面。鱼皮那面先朝上来烤,再翻面,可以烤出完整的鱼皮。

由于浸泡盐水和烤炙,鱼肉的水份大部分流失,使得鱼的鲜味浓缩,所以吃起来味道很棒!