邵毅 何美 陳春
關(guān)鍵詞:Flutter;Golang;Socket;山羊孕測
中圖分類號:TP311 文獻標識碼:A
文章編號:1009-3044(2023)03-0040-04
隨著移動應用在廣大群眾中的廣泛使用頻率提高,更多的B端產(chǎn)品逐步轉(zhuǎn)向到移動端,其中原生App 的高性能滿足較多場景的使用,隨著技術(shù)發(fā)展,跨平臺方案逐步推廣,引出眾多跨平臺技術(shù),如React Native、Weex、Flutter等。2018年谷歌開源Flutter1.0至今3.3 在跨平臺的高性能與開發(fā)便捷不斷受到廣泛青睞。本文將在已使用Java SpringBoot設(shè)計的山羊孕測管理系統(tǒng)平臺的基礎(chǔ)上采用Flutter框架開發(fā)一套山羊孕測App,實現(xiàn)視頻監(jiān)控、即時通訊、異常通知等功能,為提升與山羊孕測管理系統(tǒng)平臺的高性能多線程數(shù)據(jù)處理能力使用Golang語言開發(fā)接口SDK包。有效提高專家、管理員、員工通過App進行對山羊懷孕檢測、山羊狀態(tài)進行監(jiān)控與管理,使用Flutter進行一套代碼開發(fā),編譯出原生代碼在Android、iOS平臺上運行,節(jié)省了開發(fā)成本,同時也提高了App的運行效率。
1 山羊孕測App 設(shè)計
1.1 Flutter 框架介紹
Flutter 是Google 開源的應用開發(fā)框架,使用Dart 語言開發(fā),僅需要一套代碼就能構(gòu)建精美的、原生平臺編譯的多平臺應用軟件。Flutter可快速直接編譯成ARM或者Intel 平臺的機械代碼,確保擁有原生平臺運行的性能表現(xiàn)能力,高效地使用熱重載(Hot Reload) 在開發(fā)中快速更新實時預覽并不丟失狀態(tài),在屏幕上,可靈活地將每個像素都由你來把握。在Flutter3.3版本開始逐步引入新的圖形引擎: Impeller,提供了絲滑的動畫效果,使用Impeller 的應用可以保持60Hz 或者更快的刷新率的同時,能夠比以前更進一步地突破界限。Flutter代碼由Dart語言編寫,該語言提供允許編譯為iOS和Android的32位和64位的機械碼,以及在Web 允許的JavaScript和桌面設(shè)備,并且開源、免費和社區(qū)開發(fā)者的不斷增加,現(xiàn)已被廣大開發(fā)者使用[1]。
1.2 Go語言介紹
Go語言(Golang) 起源于2007 年,是由Google 的Robert Griesemer,Rob Pike 及Ken Thompson 開發(fā)的一門編譯型語言。具有部署簡單、并發(fā)性能好、設(shè)計與執(zhí)行能力好、支持垃圾回收功能、跨平臺編譯運行等優(yōu)點。具有Gomobile是一個應用于iOS和Android 的優(yōu)秀跨平臺開發(fā)庫,為開發(fā)者提供創(chuàng)建Android或iOS移動平臺代碼的工具。
1.3 山羊孕測設(shè)計
針對性能與降低開發(fā)成本,F(xiàn)lutter具有較好的狀態(tài)管理以及極快的UI便捷開發(fā)與跨平臺的支持。在實時數(shù)據(jù)更新與數(shù)據(jù)接口請求,考慮到高并發(fā)、跨平臺、低成本開發(fā)[2],使用Socket連接,實時進行數(shù)據(jù)通信觸發(fā)數(shù)據(jù)更新接口下發(fā)更新通知,從性能方面考慮,選擇使用Go語言進行編寫后端與App之間數(shù)據(jù)交互的橋梁,編譯出與后端數(shù)據(jù)交互的SDK,方便在多場景下集成使用[3]。并使用Flutter 提供Method?Channel通信方式,在Native和Flutter的進行調(diào)用原生的代碼。其中用到狀態(tài)管理插件在Provider、GetX、Bloc、Redux中從難易度上考慮,其中Provider的使用簡便,但是它需要更多的框架搭建與處理全局上下文的問題,因此選擇GetX狀態(tài)管理,它的使用簡單,并對全局context上下文提供了對應的方法,在業(yè)務邏輯中方便地調(diào)用以及對各個頁面之間進行跨頁面的狀態(tài)更新。避免過多重復的Widget 組件實現(xiàn),對重復使用頻率高的組件進行封裝,提高了代碼質(zhì)量,方便在各個頁面之間直接調(diào)用,避免重復UI 邏輯實現(xiàn),并針對重復調(diào)用方法邏輯進行封裝到統(tǒng)一的Controller 控制器中由GetX狀態(tài)管理方便調(diào)用,提高了代碼閱讀性[4]。
1.4 山羊孕測App網(wǎng)絡(luò)請求拓撲圖
山羊孕測App首次啟動進行登錄,向后端發(fā)送請求,通過網(wǎng)關(guān)授權(quán)后從后端應用服務器獲取數(shù)據(jù)信息進行初始化SDK接口并建立Socket 連接,監(jiān)聽數(shù)據(jù)更新。當觸發(fā)監(jiān)控頁面時連接視頻監(jiān)控視頻推流地址呈現(xiàn)畫面在App,所有數(shù)據(jù)通過SDK進行發(fā)起數(shù)據(jù)請求返回到App呈現(xiàn)數(shù)據(jù)。在避免重復的登錄操作,使用了無狀態(tài)Token 校驗權(quán)限,在每個請求中均攜帶Token請求,后端服務校驗通過后,返回數(shù)據(jù)[5]。圖1為網(wǎng)絡(luò)請求拓撲圖。
1.5 山羊孕測App 功能
山羊孕測App底部導航主要劃分為首頁、資訊、消息、我的四個主要頁面入口。首頁:包含山羊數(shù)據(jù)列表,每個山羊可點擊查看具體基本信息、其他觀察、超聲波、預警推送、生物激素、專家意見、視頻監(jiān)控、當日事件等功能。資訊:提供相關(guān)的資訊內(nèi)容閱讀。消息:為增強即時通訊能力,用于專家、員工、管理員之間的消息即時溝通能力。我的:提供個人信息資料修改,管理員可對用戶和山羊信息進行管理維護,功能結(jié)構(gòu)如圖2-①。除消息頁面(即時通訊)為通用功能、資訊頁面與我的頁面?zhèn)€人信息修改外,在登錄頁面可以通過申請賬號功能頁面申請賬號、忘記密碼、登錄賬號三項功能,在登錄成功后根據(jù)申請賬號時申請的角色權(quán)限不同將功能細分:管理員擁有管理后臺、推送版本、修改參數(shù)功能,專家與員工角色同時具備查看信息、查看監(jiān)控、推送預警、日歷事件,專家額外擁有編輯建議、推送狀態(tài)功能權(quán)限,員工額外擁有上傳圖片權(quán)限。如圖2-②所示。
2 山羊孕測實現(xiàn)與關(guān)鍵技術(shù)
2.1 服務端與App端數(shù)據(jù)交互
Flutter編寫App在進行數(shù)據(jù)交互時候,需要與后端業(yè)務通過API接口與Socket通道進行交互。在本App設(shè)計中使用Golang對后端業(yè)務接口進行封裝成SDK API,F(xiàn)lutter需要進行SDK初始化后端接口地址,通過調(diào)用接口與后端進行交互,并使用SDK初始化Socket建立連接,實時更新山羊狀態(tài)數(shù)據(jù),通過GetX 狀態(tài)管理對UI狀態(tài)更新。
2.2 App 頁面功能實現(xiàn)[6]
圖3為山羊孕測App實現(xiàn)部分頁面圖,詳情見下:
1) 底部導航:使用自定義BuildNavigation底部導航組件傳入Scaffold 腳手架的bottomNavigationBar 生成底部導航,在腳手架body中使用IndexedStack組件記錄當前導航索引進行切換頁面,效果如圖3-① 所示。
2) 首頁:使用GetX中Controller控制器初始化數(shù)據(jù)并建立Socket連接監(jiān)聽數(shù)據(jù)變化,關(guān)鍵代碼如下:
initSocket() async {
var socket = await Socket.connect(Api.socket, Api.
socketPort);
socket.listen((event) {
initAllSheepData();
update(['MainMHO']);
});
使用card_swiper插件完成輪播組件,選項卡區(qū)域使用TabBar組件實現(xiàn),效果如圖3-②所示,選項卡中數(shù)據(jù)使用GetBuilder定義id并包裹ListView列表組件加載山羊數(shù)據(jù),在監(jiān)聽數(shù)據(jù)變化時,通過GetX中up?date()方法傳入定義id值進行局部組件更新。
在點擊每個山羊詳情卡片式組件進入詳情頁面時候,優(yōu)先進行權(quán)限校驗,根據(jù)權(quán)限不同,所使用的功能權(quán)限不同。在無權(quán)限時將提示無權(quán)訪問彈窗并返回至首頁。所有按鈕使用GestureDetector與Container 進行封裝成可自定義顏色、圖片、內(nèi)容的Widget組件,避免過多重復代碼編寫。員工使用確定懷孕與取消確定觸發(fā)Socket發(fā)送廣播通知其他在線用戶狀態(tài)更新,關(guān)鍵代碼如下:
putDescribe(int id, String msg) {
Get.back();
SheepApi.putSheep({
"sheepId": id,
"sheepDescribe": msg,
}).then((value) {
initSheepData(state. sheepModel. value. data!.
sheepId!);
});
包含了生物激素,超聲波,其他觀察,運動,溫度,日歷,智慧耳標,視頻監(jiān)控,AI助手、當日記事,預警推送、取消預警,專家意見。點擊進入“生物激素,超聲波,其他觀察,運動,溫度,日歷,智慧耳標,視頻監(jiān)控”可以進入功能詳情頁查看信息執(zhí)行相關(guān)操作。通過各指標信息的查看,管理員點擊進入“預警推送、取消預警”可以對山羊是否懷孕進行預警和撤銷。點擊進入“專家意見”可以查看專家給的相關(guān)意見,但不能修改。點擊進入“AI助手”,可為將來AI功能提供擴展接口。點擊進入“當日記事”,可在日歷記錄當日山羊情況[7],效果如圖3-③所示。
專家登錄時,可對專家意見中內(nèi)容進行編輯,內(nèi)容編輯使用flutter_quill富文本插件實現(xiàn),員工只能進行查看內(nèi)容不可編輯,效果如圖3-④ 所示。
運動與溫度數(shù)據(jù)通過調(diào)用后端接口獲取傳感器數(shù)據(jù)得到當天每半小時的數(shù)據(jù)[8]。其中日歷部分使用bruno 插件完成UI功能,并可通過當日記事按鈕提交當日事件記錄。關(guān)鍵代碼如下:
changeDateTime(DateTime date?Time) {
String calendarDate = ' ${dateTime.
year} - ${dateTime. month} - ${dateTime.
day}';
CalendarApi.getCalendarByDate(
Get. arguments['sheepId']. toString(),
calendarDate, '1')
.then((value) {
state. listCalendarModel. value =
value.data!;
});
}
void postCalendar() {
var date = DateTime.now();
String calendarDate = '${date.year}-${date.month}-
${date.day}';
CalendarApi.postCalendar(
Get.arguments.toString(),
calendarDate,
'1',
'山羊狀況記錄: ${state.text}',
).then((value) {
if (value.data!.code == 20000) {
contextFocusNode.unfocus();
Get.dialog(
ShowLoading(
text: '${value.data!.msg}',
),
).then((value) {
Get.back();
});
}
});
}
視頻監(jiān)控頁面在完成后端數(shù)據(jù)鑒權(quán)后獲取到監(jiān)控視頻推流地址,路由并攜帶推流地址到視頻播放頁面,通過調(diào)用better_player插件初始化后,視頻進行加載播放,在返回頁面時候銷毀播放器避免視頻常駐后臺播放占用內(nèi)存與帶寬占用,關(guān)鍵代碼如下:
AspectRatio(
aspectRatio: 16 / 9,
child: BetterPlayer.network(
Get.arguments,
betterPlayerConfiguration: const BetterPlayerCon?
figuration(
autoPlay: true,
aspectRatio: 16 / 9,
),
)3) 資訊:通過調(diào)用封裝的SDK接口,請求資訊數(shù)據(jù),效果如圖3-⑤所示。初始加載20條數(shù)據(jù)并在滑動頁面最后一條數(shù)據(jù)時觸發(fā)加載更多數(shù)據(jù),每次觸發(fā)加載遞增20條數(shù)據(jù),關(guān)鍵代碼如下:
void initNewsData() {
NewsApi. getPageNews(current: current, pageSize:
pageSize).then((value) {
state.listNewsModel.value = value.data!;
});
}4) 消息:為了方便工作人員之間的及時的溝通處理能力,集成tim_ui_kit插件,完成簡單的即時通訊功能業(yè)務能力[9],效果如圖3-⑥所示。關(guān)鍵代碼如下:
initTencentIMSdk() {
_coreInstance.init(
sdkAppID: Config.sdkAppID,
loglevel: LogLevelEnum.V2TIM_LOG_DEBUG,
listener: V2TimSDKListener());
}
final MessageState state = MessageState();
final TIMUIKitConversationController controller =
TIMUIKitConversationController();
@override
void onInit() async {
super.onInit();
controller.loadData();
controller.setConversationListener(
listener: V2TimConversationListener(
onNewConversation: (conv) {
update();
},
onConversationChanged: (conv) {
update();
},
),
);
}5) 我的:調(diào)用封裝的SDK獲取個人信息后,通過個人信息中指定角色判斷,管理將額外顯示用戶管理、山羊管理入口按鈕,效果如上圖3-⑦所示。關(guān)鍵代碼如下:
void updateUserInfo() {
String? faceUrl;
if (state.faceUrl.value != '') {
faceUrl = state.faceUrl.value;
}
UserApi.updateUserInfo(
state.userInfo.value.data!.userId!,
faceUrl!,
nicknameController!.text,
emailController!.text,
).then((value) async {
// 更新IM頭像
V2TimUserFullInfo userFullInfo = V2TimUserFull?
Info();
userFullInfo. userID = state. userInfo. value. data!.
username;
userFullInfo.faceUrl = Api.baseUrl + faceUrl!;
userFullInfo.nickName =
nicknameController!. text ! = '' ? nicknameCon?
troller!.text : '';
V2TimCallback v2timCallback = await TIMUIKit?
Core.getSDKInstance()
.setSelfInfo(userFullInfo: userFullInfo);
if (v2timCallback.code == 0) {
iniUserInfo();
Get.back();
}
});
}
3 性能效果分析
通過Android Studio 的Flutter 插件提供的FlutterInspector進行調(diào)試觀察FPS浮動情況,得到一個良好的效果,均保持在60FPS左右的范圍,如圖3-⑧所示。通過校內(nèi)學生100人在多種不同機型的安裝下使用,對山羊孕測App進行多個頁面的高頻率反復隨機點擊操作和查看各種功能,無任何閃退情況,各項功能正常。Socket連接中無斷連,并均能收到實時數(shù)據(jù)更新提示,消息的互發(fā)及時溝通無任何數(shù)據(jù)丟失。
4 結(jié)束語
山羊孕測App的開發(fā),通過對業(yè)務框架設(shè)計,將業(yè)務邏輯、UI、數(shù)據(jù)分離設(shè)計開發(fā),降低耦合性,對各項傳感器的高性能連接,保障了產(chǎn)品業(yè)務的高可用性。通過Flutter與Go語言的跨平臺特性節(jié)省了開發(fā)成本。