NLChat的一周开发总结,从0到1做出了很多聊天功能出来了。 原创
我们的上篇文章:点我访问
很高兴来到这一篇文章的大家,我写这篇文章时是2024年7月1日,先在讲开发总结前,庆祝我们国家建党节103周年一下。
今天的内容大体上是对软件的功能更新,还有一些我个人的小插曲,同时也会给大家讲清我们功能的写法。
首先就是第一点,这一点对大家,对Android用户都很重要。一直以来,我们开源的项目,在处理Release发布时,我们的后台操作,经常耗时费力,这很不利于我们++NLChat++聊天软件的开源仓库向大家见面。
那么,来到我们第一个重点了,也就是:自动化构建!
在30号,我打通好了Github Android CI自动化构建程序,省去大家Clone项目再Build的时间的同时,也能同步到Release发布。这期间,我们一直拿主仓库测试,错误了就改错重新试。直到成功,继续看看哪里可以改改,直到代码满意,自动化流程没问题,我们才结束这方面的开发。
Release发行代码:点我查看
name: Android CI Release
on:
push:
tags:
- "v*"
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- uses: gradle/gradle-build-action@v2
with:
gradle-version: current
arguments: assembleRelease
- uses: r0adkll/sign-android-release@v1
id: sign_app
with:
releaseDirectory: app/build/outputs/apk/release
signingKeyBase64: ${{ secrets.SIGING_KEY }}
alias: ${{ secrets.ALIAS }}
keyStorePassword: ${{ secrets.KEY_PASSWORD }}
keyPassword: ${{ secrets.KEY_PASSWORD }}
env:
BUILD_TOOLS_VERSION: "34.0.0"
- run: mv ${{steps.sign_app.outputs.signedReleaseFile}} NLChat_$GITHUB_REF_NAME.apk
- uses: ncipollo/release-action@v1
with:
artifacts: "*.apk"
token: ${{ github.token }}
generateReleaseNotes: true
我们NLChat软件,从发行的开始使用教新的Gradle编译、Java17主流版本、Android SDK 34版本打包签名,确保我们的软件在新设备上运行不出问题。至于隔壁Debug的自动化流程,我就不在此放出来了。
来到第二点,不知道大家有没有注意,我们的README有了许多变化。
作为一个认真搞开源程序的我们,在开发的途中走在前人走过的路上,永远都是我们的最佳必经之路,所以,我们添加了众多作者们(包括Github官方)的开源协议。向您们表达感谢。
接下来就来到我们的重头戏了,我们做好了SQLite部分相关功能。
7月1号当天,我在上午推送了1.2.16这个版本。点我下载体验旧版
该版本作为我们第一次公开展示聊天记录保存的细节,其实就是用到了SQLite来做到的功能。接下来就是代码讲解环节了。
如果我们想在Android上使用SQLite,本质上跟电脑上的SQL、MongoDB一样,我们的第一步永远都是添加支持,第二步添加数据库文件,第三步++理清数据库框架++,第四步增删改查,虽然我目前只写到“增”,但也快了,该有的功能都会如期而至公开开源出来的。
首先,让我们创建一个类,这个类,必须包括上面的“一二三四”四个操作的函数,并保留“增”、“查”这些接口。那么,代码将是如下写法:
public class SQLiteDataBaseAPP {
SQLiteDatabase sqLiteDataBaseForAPP,sqLiteDataBaseForUser,sqLiteDataBaseForChat,sqLiteDataBaseForDevice;
protected SQLiteDataBaseAPP() { }
public static SQLiteDataBaseAPP SQLiteData() { return SQLiteDataBaseAPP.data.shuju; }
protected static class data { private static final SQLiteDataBaseAPP shuju = new SQLiteDataBaseAPP(); }
public void CreateSql(String SDPath) {
sqLiteDataBaseForAPP = SQLiteDatabase.openOrCreateDatabase(SDPath + "/NLChat.db",null);
sqLiteDataBaseForUser = SQLiteDatabase.openOrCreateDatabase(SDPath + "/NLChatUser.db", null);
sqLiteDataBaseForChat = SQLiteDatabase.openOrCreateDatabase(SDPath + "/NLChatChat.db",null);
createChatTable();
sqLiteDataBaseForDevice = SQLiteDatabase.openOrCreateDatabase(SDPath + "/NLChatDevice.db",null);
}
private void createChatTable() {
String TABLE_CREATE =
"CREATE TABLE IF NOT EXISTS messages (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"message TEXT, " +
"sender TEXT, " +
"timestamp TEXT);";
sqLiteDataBaseForChat.execSQL(TABLE_CREATE);
}
public void saveMessageToDatabase(String message, String sender, String timestamp) {
ContentValues values = new ContentValues();
values.put("message", message);
values.put("sender", sender);
values.put("timestamp", timestamp);
sqLiteDataBaseForChat.insert("messages", null, values);
}
public Cursor getAllMessages() {
return sqLiteDataBaseForChat.query("messages", null, null, null, null, null, "timestamp ASC");
}
}
通过saveMessageToDatabase(…),这个方法,我想大家都能知道我目前做的数据库多简单了吧,如图所示,我们就保存了用户的消息、谁发送谁接收和时间戳。
你想问我为什么现阶段用明文存储?我的答案其实很简单:目前SQL文件存储位于/data/user/0/软件包包名/files这个文件夹下,该路径为Android系统权限锁死的地方,除非开发者或用户对手机进行了ROOT获取后提权访问该文件夹获取SQLite文件,否则通过其他途径无法获得该文件。
当然,这一次更新,不止有SQLite这个功能,还有滚动消息功能。
滚动消息,顾名思义,就是对已经存在UI屏幕上许久的聊天文本,我们其实可以通过代码来做到被下一句消息顶替的。之所以之前我们没有这个功能,而是现在才有这个功能,还是因为我感觉如果任由TextView一直显示大量之前的信息,观赏性阅读性会变差。
所以,我在ChatUtils类里,添加了boolean变量,这项功能目前还仅仅是做到代码里修改是否开启,后续会集成进UI里。
public class ChatUtils {
//这里设置的是UI相关,是否做到消息滚动展示在UI上,而不是全部展示,全部展示会占用大量UI资源
private static final boolean scrollingMessages = true; // 控制是否启用滚动消息功能
......
//控制是否启用滚动消息功能
public static boolean isScrollingMessages() { return scrollingMessages; }
......
}
添加了这个boolean变量,我们接下来的软件是否用到这个功能就取悦于我们手动true or false了,那么,我们也要对ReadData和SendData读和发送相关代码,做进一步的修改,确保我们想要的功能可控开关还能实现,读取相关代码如下:
//处理完再打印到UI上
runOnUiThread(() -> {
saveMessageToDatabase(processedString, "User");
if (ChatUtils.isScrollingMessages()) {
if (serverMessageQueue.size() >= MAX_MESSAGES * 3) {
serverMessageQueue.poll();
}
serverMessageQueue.add(processedString);
updateServerTextView();
} else {
NearLinkServerText.append(processedString);
if (NearLinkServerText.length() > 2048) {
String str = NearLinkServerText.getText().toString().substring(NearLinkServerText.getText().length() - 1024, NearLinkServerText.getText().length());
NearLinkServerText.setText("");
NearLinkServerText.append(str);
}
}
});
发送相关,我们也有做修改,本质上,就是是true(启用)后,我们的MessageQuete这个LinkedList变量,相当于是一个队列存储俩端消息。发行队列满了,则移除最早的消息,再添加新消息到队列。发送相关代码也是一样,代码如下:
runOnUiThread(new Runnable() {
@Override
public void run() {
saveMessageToDatabase(TextOfClient, "Me");
if (ChatUtils.isScrollingMessages()) {
if (clientMessageQueue.size() >= MAX_MESSAGES) {
clientMessageQueue.poll(); // 移除最早的消息
}
clientMessageQueue.add(TextOfClient);
updateClientTextView();
} else {
NearLinkClientText.append(TextOfClient);
if (NearLinkClientText.length() > 2048) {
String str = NearLinkClientText.getText().toString().substring(NearLinkClientText.getText().length() - 1024, NearLinkClientText.getText().length());
NearLinkClientText.setText("");
NearLinkClientText.append(str);
}
}
}
});
借助生活中便捷的灵感,我们这款NLChat也开发了一个小功能:添加聊天剪贴板。
这个功能是为什么会做出来的呢?是因为我发现,我们在使用多部手机时,可以做到把验证码发给另一部设备,自动写入剪贴板后粘贴到软件上输入验证码完成登录等验证。那么这个功能就是因为这个idea发明了出来,代码如下:
//聊天进入剪贴板
if (ChatUtils.isClipMessages()) {
// 提取四位和六位数字
Pattern pattern = Pattern.compile("\\b\\d{4}\\b|\\b\\d{6}\\b");
Matcher matcher = pattern.matcher(completeSecondData);
while (matcher.find()) {
String foundNumber = matcher.group();
extractedNumbers.append(foundNumber).append("\n");
}
// 将提取到的数字复制到剪贴板
if (extractedNumbers.length() > 0) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("extractedNumbers", extractedNumbers.toString().trim());
clipboard.setPrimaryClip(clip);
SnackBarToastForDebug("提取到疑似验证码,已复制到剪贴板!","推荐去粘贴",0,Snackbar.LENGTH_LONG);
}
}
目前这个功能可能会遇到Bug,我会在后面修复相关问题。
完成了这么多功能,我还修复了SQL相关的Bug,之前的代码可能存在SQL写入空行的逻辑问题。
如图就是我在Test时遇到的情况:
那么,这样的问题该怎么解决呢?其实很简单,检测添加进SQL时如果没有内容则不添加不就好了,代码如下:
private void saveMessageToDatabase(String message, String sender) {
//检索是否有空消息,串口通讯时常有相关问题
if (message == null || message.trim().isEmpty()) {
return;
}
//如果有消息再保存,上面是没消息不予保存
......
}
写到最后,来些轻松的话题,这么多天,我不但在添加软件功能修复Bug,还有做着许多测试呢。
第一张图是做压力测试呢OvO,我自己是很满意这样的单向通信,当然,我是用一款无障碍自动点击做到这么点击的(40ms的一次click)
还有很多所谓的开发瞬间我就因为篇幅不多放了,希望大家见谅。
最后一个好消息,我们这款NLChat软件,已经报名参加了星闪开发者体验官活动。
已经报名了哦,那么,我们这款软件的开发周期,将会延长到比赛结束,请大家不必担心功能问题。
End.
2024.7.2
学到了,感谢分享。
各个环节确实都不容易