合作独立开发项目:Daak记账
这是和大学同学合作开发的财务应用项目,目前已经上架国内外各大平台,iOS版本是同学独立开发的,Android版本是我独立开发的,后者刚起步不久,希望大家多多支持~
下面是下载方式和初版的一些简介,直接从我们的官网搬运过来的:daakapp.com
Daak记账 - 简洁可爱日常收支随手记账本中文 | English
Daak记账,功能齐全,简洁可爱,非常适合新手记账
下载iOS
Apple Store
Android
Google Play
安卓
中国用户请点击下方链接或到应用商店搜索“Daak记账”
华为
小米
OPPO
vivo
温馨提示 -> 由于小米为了商业化利益考虑,禁用了Android标准规范的 market:// 链接本应呈现的功能。
因此点击上述小米应用商店的链接后,可能并不会直接打开我们的应用详情页面,请手动搜索“Daak记账”下载安装,谢谢~
介绍功能齐全
支持Apple Watch以及多种小组件
自定义一二级记账分类
多账本、多人记账、多币种功能
预算、资产账户、债务(借入/借出)管理
退款、报销、分期还款
账单支持添加图 ...
给MIUI开发一个刷新率开关
背景我们很容易发现,现在小米等厂商支持高刷新率120Hz的手机,在系统设置中都隐藏了90Hz这个档位,只有60和120两种选项。对很多人来说,60虽然省电但是太不流畅,影响体验,120虽然流畅但太耗电,出门会有电量焦虑,折中的90其实才是最合适的选择(至少在心理上)。
我一直试图搞清楚为什么厂商不愿意开放90Hz这个选项,对系统来说,刷新率无非就是一个可以修改的数值。是什么原因不让用户多一个选择呢?
调查经过一些简单的查询,我发现网络上的解释一般都是硬件本身不支持,芯片功能较弱,不足以驱动多种刷新率,强制修改为90Hz长时间可能造成屏幕损坏等。
当然,我也不忘去问一问无所不知的ChatGPT,他还是一如既往地说了一些车轱辘话。他这个“技术退步”论倒是有点意思。
其实“硬件不支持”这个说法我并不是很赞同。如果你在Android系统的开发者选项中打开“显示屏幕刷新率”的开关,就会发现在不同的使用场景下,不只有60Hz和120Hz两种刷新率,比如息屏AOD为了降低功耗,就只有30Hz;很多手游最高也只支持90Hz,即便开启120Hz也没用。因此,要是说强制修改为其他隐藏刷新率会导致屏幕损 ...
Android系统无限重启漏洞
2022年,一次偶然的机会,我发现了一个会导致Android系统无限重启致使设备完全不可用的高危漏洞,遂提交给了Google。当年11月的AOSP补丁对此进行了修复,本文是我提交漏洞报告的原文,现公开,待整理。具体可以在Android Security Bulletin—November 2022中搜索CVE-2022-20414了解更多。
最后有幸上了Google官方的致谢名单:Android 安全性致谢 2022,也算是为这破碎的世界做了一点贡献吧。
Report description
In a few words describe your bug. This will help you search for it later.
The “snoozeNotification” method of NotificationListenerService causes Android system to crash and cyclic reboot.
Bug locationWhich product or website have you found a vulnera ...
如何用crontab和mail定时发邮件
背景虽然说懒人炒股不一定能赚到钱,但是懒人自有偷懒的办法。
最近突发奇想,想在服务器上设置一个定时任务,每隔一段时间查询某只股票的股价,如果达到告警条件,就自动发一封邮件给指定邮箱。正好QQ邮箱还接入了Android的系统级推送,这样我就不用每天盯盘了。
准备先准备一个163邮箱,其他邮箱也行(支持开启SMTP服务即可),这里以163邮箱为例。
登录网页版,找到“设置”-“POP3/SMTP/IMAP”,然后点击“新增授权码”,复制这个授权码先暂存,等会儿要用。
基础设施我的小水管服务器是Ubuntu 16.04,所以下面就基于这个环境来搞。
为了能用命令发邮件,我们先安装相关的依赖:
1apt install mailutils
首次安装后,会出现一个粉紫色界面,提示你配置“Postfix Configuration”,这里直接选择“No configuration”,然后OK。
接着安装ssmtp服务:
1apt install ssmtp
安装完后编辑此配置文件 vim /etc/ssmtp/ssmtp.conf,添加并保存如下内容:
12345root= ...
如何禁用网站目录访问(Apache)
问题以Ubuntu 22.04(其他LTS版本类似)和Apache2服务为例,我们一般会把网站资源放在 /var/www/html 中,又比如把提供给用户下载的安装包放在 download 目录下面,那么最终的下载链接就是:
https://xxx.com/download/abc.apk
这个 download 目录下面可能不只有一个apk,而是很多个资源文件,默认情况下,如果用户好奇打开https://xxx.com/download/,就会直接看见该目录下所有文件,甚至还可以逐级往上查看父目录。
有时候这并不是我们想要的结果,用户可能会看见我们未公开链接的资源,造成一些。
解决本来问了一下各种GPT,发现给的答案都太麻烦了,而且还不一定靠谱。最终还是从互联网的汪洋中找到了一个简单的办法。
直接编辑Apache的配置文件:
1vim /etc/apache2/apache2.conf
按I进入编辑模式后,找到这部分内容:
12345<Directory /var/www/> Options Indexes FollowSymLinks Al ...
Levenshtein编辑距离算法初体验
在做字符串相似度匹配时很有用,我更愿意叫它“相似度算法”~
简介Levenshtein算法,又称编辑距离算法,是一种用于计算两个字符串之间最小编辑操作数的算法。编辑操作包括插入、删除和替换字符。该算法由苏联科学家Vladimir Levenshtein于1965年提出。
编辑操作Levenshtein距离通过以下三种基本操作来衡量两个字符串的相似度:
插入:在字符串中插入一个字符。
删除:从字符串中删除一个字符。
替换:将字符串中的一个字符替换为另一个字符。
算法实现Levenshtein算法通常使用动态规划来实现。其核心思想是通过构建一个二维矩阵来记录两个字符串之间的编辑距离。具体步骤如下:
初始化矩阵:
创建一个大小为 (m+1) x (n+1) 的矩阵,其中 m 和 n 分别是两个字符串的长度。
矩阵的第一行和第一列分别填充 0 到 m 和 0 到 n 的值。
填充矩阵:
对于矩阵中的每个元素,计算其值。该值等于以下三个值中的最小值加1:
左边的值(表示删除操作)
上面的值(表示插入操作)
左上角的值(表示替换操作,如果字符相同则不加1)
返回结 ...
用MySQL的FROM_UNIXTIME函数转换时间格式
假如我在MySQL数据库中有一个订单表,结构如下:
status
pay_method
update_time
1
2
1724403637114
其中 update_time 是bigint类型,对应Java/Kotlin代码中的Long类型,用以存储时间戳,用MySQL的bigint而不是timestamp类型,也能避免2038年上限的尴尬问题。
当然,得到一样东西很可能失去另一样东西,那就是“可读性”,我们在查询数据的时候,一眼是看不出来这个 1724403637114 具体是什么时间的。能不能既要又要呢?保证存储格式不变的情况下,查询的时候还能显示成更可读的时间格式。
这时候就可以用MySQL的函数了:FROM_UNIXTIME,它可以在查询的时候帮你格式化时间戳!我们直接看SQL语句:
1SELECT status, pay_method, FROM_UNIXTIME(update_time / 1000, '%Y-%m-%d %H:%i:%s') AS update_time FROM order;
因为此函数输入参数的单位是 ...
如何限制只能通过域名访问网站(Apache)
背景最近突发奇想,怎么让基于Apache服务的网站只能通过域名访问?也就是说,在浏览器地址栏直接输入IP就不允许访问。这样有个好处就是,必须是知道域名的用户才能访问网站内容,如果只是通过某种方式捕获到IP,不让他知道网站运行着什么内容。
基础我的服务器环境是Ubuntu 16.04,其他版本的系统也差不多,只要是Apache 2.x版本就行。并且,网站支持了HTTPS访问。
首先,确保Apache服务器已经启用了 mod_rewrite 模块:
123sudo a2enmod rewrite# 重启Apache服务sudo systemctl restart apache2
配置接下来,我们就通过修改配置来实现需求。先找到配置文件:
1cd /etc/apache2/sites-available/
此目录下一般有 000-default.conf 和 default-ssl.conf 这两个文件,因为支持了HTTPS,所以我们直接修改后者:
1234567891011121314151617<IfModule mod_ssl.c> <VirtualHost ...
解决git提交出现RPC failed HTTP 400的问题
最近升级了macOS系统后(从12.5升到12.7),发现我的Hexo博客部署不上去了,执行:
1hexo clean & hexo deploy
会提示错误:
12345678Counting objects: 19815, done.Compressing objects: 100% (5264/5264), done.Writing objects: 100% (19815/19815), 44.91 MiB | 134.87 MiB/s, done.Total 19815 (delta 14641), reused 19405 (delta 14283)error: RPC failed; HTTP 400 curl 22 The requested URL returned error: 400 Bad Requestfatal: The remote end hung up unexpectedlyfatal: The remote end hung up unexpectedlyEverything up-to-date
看到400错误,还以为是权限有问题,尝 ...
让WCDB兼容最新版Room
先直接推荐我的开源小库:WCDBRoomX ,如果它的README就已经让你知道库的核心作用,这篇文章就不需要看了。
WCDB是腾讯微信团队开源的客户端数据库框架,拥有高性能和支持加密等重要特性,并且可用于Android、iOS、Windows、macOS等多个平台。 我们知道,原生的加密数据库框架SQLCipher和不加密的SQLite相比,性能差距还是很大的,加密会使得读写效率严重下降,而WCDB很好地兼顾了性能和安全问题。
SQLCipher和SQLite对比测试
WCDB和SQLite对比测试
对使用了Google官方Jetpack Room库的开发者,WCDB 1.x版本也提供了完美支持:Use WCDB with Room ,然而,WCDB 2.x版本后变成了一个纯ORM框架,虽然也支持Java、Kotlin等语言(本质上就是一层封装,底层接口都一样),但是暂时没有计划支持兼容Room,从官方文档看,2.x版本更纯粹,一套代码跨全平台,所以也不关注各平台的其他框架兼容了。
跟WCDB的开发者也聊了聊,他们团队对Room的支持兴趣不大:issues#1052 。其实 ...
双进程交互实现App自动重启
背景你可能会好奇,有些手游(比如王者荣耀)是怎么实现资源更新后自动重启的?
这个体验确实不错,因为不需要用户手动点击桌面图标重启App,在一些数据恢复备份的场景中,很实用。比如,从云端拉取SQLite数据库db文件或一些prefs配置文件后,会直接覆盖到本地,但进程不重新启动的话,是不会生效的。
思路基本思路其实很简单,利用Android应用对多进程的天然支持,来实现双进程互拉。
有的朋友一看见“双进程”、“互拉”这些词汇就会立马联想到保活,注意本文不是讲保活的哦。
为了方便讲解,我们定义主进程之外的另一个进程为 进程B。大致流程分这么几步:
在主进程执行完一系列业务逻辑后,欲重启,先拉起进程B
进程B启动后,主进程kill掉自己
接着,进程B拉起主进程,然后再kill掉自己,此时主进程完成自动重启
实现先在Manifest中声明进程B,为了良好的交互体验,需要实现一个Activity,进程名称自定义,比如此处叫“killer”,是不是很贴切?
12345<activity android:name=".KillerActivity" an ...
在assembleRelease之前执行自定义任务
背景在实际的Gradle项目开发中,我们总是会遇到一些需求,要在release编译的时候执行一些任务,但debug时不需要。然而,Gradle编译有自己的一套生命周期,比如Android项目的assembleRelease任务在编译启动之前是没有办法静态获取到的。
下面我们就以“去除release版本中的logcat日志打印”为例,做一个简单的梳理。
源码修改模板(module)级别的 build.gradle.kts 文件,我们初步目标是在编译刚启动但还没实际开始执行任务时插入我们的自定义任务,切入点就是Gradle的preBuild任务,这个是预定义的,所以可以进行静态配置:
1234567891011121314151617181920212223242526272829plugins { id("com.android.application") id("kotlin-android") id("kotlin-kapt")}android { namespace = ...
解决macOS执行fastboot找不到设备的问题
背景最近准备给我的备用机Redmi Note 11 5G刷个类原生的三方ROM,MIUI实在是用腻了。搜罗了一番,在XDA上找到了一个基于Pixel Experience开发的ROM:PixelExperience Plus for Redmi Note 11T/11S 5G/11 5G/POCO M4 Pro 5G (everpal),它的实际开源地址是:github.com/Xiaomi-MT6833/releases/releases/,可以直接在里面下载到最新的ROM刷机包和boot.img文件。
下载好PixelExperience_Plus_everpal-13.0-20230410-1707-UNOFFICIAL.zip和boot.img之后,开始刷机,其实过程非常简单(参考:小米手机刷PixelExperience系统操作指南),保证手机已经先解锁BL,并和电脑连接,然后终端执行命令,忽略指南中刷vendor那一步:
123adb reboot-bootloaderfastboot flash boo ...
给不蒜子(busuanzi)统计数据增加初始值
背景最近把个人博客迁移到了Hexo框架,并使用了Butterfly主题,得益于博客框架的易用性和主题功能的丰富程度,感觉非常的香。我对比了很多Hexo主题,这一个算是在功能、审美、文档等各方面几乎完美符合我需求的。
Butterfly很贴心地集成了不蒜子计数工具,可以统计网站的访问数据(人数,次数等)。只需要修改主题config文件即可开启:
1234busuanzi: site_uv: true site_pv: true page_pv: true
即便没有使用Hexo框架和Butterfly主题,用不蒜子计数也是很简单的。
这个工具存在快十年了,其首页的标语就是“两行代码,搞定计数”。感觉这位作者也是个有情怀的开发者,维护服务器给大家免费使用这么多年。
12<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script> <span id="busuanzi_container_si ...
Android系统兼容适配踩坑(持续更新)
屏幕亮度范围在Android应用层,要获取屏幕亮度,一般是通过读取系统Settings表中的配置:
1Settings.System.getInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS);
从AOSP源码可以看出,其范围是0到255,如果要修改亮度,也是通过这个key去putInt的:
1234/*** The screen backlight brightness between 0 and 255.*/public static final String SCREEN_BRIGHTNESS = "screen_brightness";
原则上无论什么设备,厂商都应该按照这个亮度范围去做类似“归一化”的适配,才能让上层开发者写出可靠的代码。
实际上,这个范围值并不可靠,很多厂商根本没在意这个源码注释中的255上限。这就导致了开发者以为修改成255就是最大亮度,但效果不符合预期。
我们可以通过获取最大亮度的配置值来验证:
12int id = getResources().getIdentifier ...