舒爾特方格游戲-關系型數據庫版本,請移步到上一篇帖子查看,本篇帖子內容還是舒爾特方格游戲,只是換了后宮_云數據庫。
此項目是用最新版 DevEco Studio 3.1 Release 并創建端云一體開發,由于目前此版本不支持直接調用云數據庫,不過可以通過云函數調用云數據庫。
也就是在服務卡片業務邏輯里通過調用云函數來完成游戲數據保存到云數據庫,開發工具支持本地函數調用測試,大大方便了開發。
此貼重點講解云函數和云數據庫開發,本地和遠端調用,從而進一步學習 Serverless 知識。
舒爾特方格游戲效果圖如下: ?知識點
為豐富 HarmonyOS 對云端開發的支持、實現 HarmonyOS 生態端云聯動,DevEco Studio 推出了云開發功能,開發者在創建工程時選擇云開發模板。
即可在 DevEco Studio 內同時完成 HarmonyOS 應用/服務的端側與云側開發,體驗端云一體化協同開發。
相比于傳統開發模式,云開發模式具備成本低、效率高、門檻低等優勢,具體區別見下表。①開發流程
HarmonyOS 應用端云一體化開發流程如下圖所示:
②創建端云一體化開發工程
新建原子化服務工程:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/agc-harmonyos-clouddev-createproject-0000001443369760-V3#section15198822192610
工程初始化配置:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/agc-harmonyos-clouddev-createproject-0000001443369760-V3#section1938317533494
端云一體化開發工程介紹:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/agc-harmonyos-clouddev-createproject-0000001443369760-V3#section20250910164411
③開發云工程
開發云函數:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/agc-harmonyos-clouddev-cloudfunctions-0000001493089797-V3
開發云數據庫:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/agc-harmonyos-clouddev-clouddb-0000001443049860-V3
④部署云工程
部署云工程:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/agc-harmonyos-clouddev-deploy-0000001493209765-V3
小結:了解這些端云一體化開發知識點后,下面圍繞舒爾特方格游戲,在云數據庫里設計卡片表結構和成績表結構,然后再編寫相關云函數,并在本地測試通過后,再測試遠程,最后在元服務業務邏輯調用云函數。
云數據庫開發講解
①objecttype 創建
展開 CloudProgram→clouddb→objecttype 右擊 objecttype 目錄,創建→Cloud DB Object Type 輸入 Object Type Name 為 t_form,點擊確認。
修改內容如下:
{
"fields":[
{
"isNeedEncrypt":false,
"fieldName":"formId",
"notNull":true,
"belongPrimaryKey":true,
"fieldType":"String"
},
{
"isNeedEncrypt":false,
"fieldName":"formName",
"notNull":true,
"defaultValue":"",
"belongPrimaryKey":false,
"fieldType":"String"
},
{
"isNeedEncrypt":false,
"fieldName":"dimension",
"notNull":true,
"defaultValue":"0",
"belongPrimaryKey":false,
"fieldType":"Integer"
}
],
"indexes":[
{
"indexName":"formId",
"indexList":[{"fieldName":"formId","sortType":"ASC"}]
}
],
"objectTypeName":"t_form",
"permissions":[...]
}
展開 CloudProgram→clouddb→objecttype 右擊 objecttype 目錄,創建→Cloud DB Object Type 輸入 Object Type Name 為 t_score,點擊確認。
修改內容如下:
{
"fields":[
{
"isNeedEncrypt":false,
"fieldName":"formId",
"notNull":true,
"belongPrimaryKey":true,
"fieldType":"String"
},
{
"isNeedEncrypt":false,
"fieldName":"matrixNum",
"notNull":true,
"defaultValue":"",
"belongPrimaryKey":false,
"fieldType":"String"
},
{
"isNeedEncrypt":false,
"fieldName":"bestScore",
"notNull":true,
"defaultValue":"0",
"belongPrimaryKey":false,
"fieldType":"Double"
}
],
"indexes":[
{
"indexName":"formId",
"indexList":[{"fieldName":"formId","sortType":"ASC"}]
}
],
"objectTypeName":"t_score",
"permissions":[...]
}
②dataentry 創建
展開 CloudProgram→clouddb→dataentry 右擊 dataentry 目錄,創建→Cloud DB Data Entry 這里先選擇上面創建的 Object Type 為 t_form,再輸入 Data Entry Name 為 form_data,點擊確認。修改內容如下:
{
"cloudDBZoneName":"widgetCard",
"objectTypeName":"t_form",
"objects":[
{
"formId":"x000001",
"formName":"卡片1",
"dimension":2
}
]
}
展開 CloudProgram→clouddb→dataentry 右擊 dataentry 目錄,創建→Cloud DB Data Entry 這里先選擇上面創建的 Object Type為t_score,再輸入 Data Entry Name 為 score_data,點擊確認。修改內容如下:
{
"cloudDBZoneName":"widgetCard",
"objectTypeName":"t_score",
"objects":[
{
"formId":"x000001",
"matrixNum":"3x3",
"bestScore":2.234
}
]
}
小結:其實 dataentry 文件可以不創建,這里對兩個表都初始化了一條數據,是方便下面的調用使用,云數據庫就是定義好表結構、權限配置就可以,數據的添加、修改、刪除、查詢都可以通過云函數來完成。
云函數開發講解
①卡片云函數創建
展開 CloudProgram→cloudfunctions 右擊 cloudfunctions 目錄,創建→Cloud Function 輸入 Cloud Function Name 為 form-func,點擊確認。卡片云函數里包含了增刪改查操作,所以在 form-func 下,創建不同的文件夾來區分,目錄結構如下:
首先說一下與云數據庫交互文件,t_form.js 對應的是云數據庫實體類,如各屬性的 get 和 set 方法,之前 FA 模式下的 DevEco Studio 端云一體化開發,支持直接調用云數據庫。現在 Stage 模式下的 DevEco Studio 端云一體化開發,還不支持直接調用云數據庫,通過云函數來調用。所以這里的云數據庫實體類,除了屬性的 get 和 set 方法外,還要手工添加一些方法。如卡片實例體類:
classt_form{
getFieldTypeMap(){
letfieldTypeMap=newMap();
fieldTypeMap.set('formId','String');
fieldTypeMap.set('formName','String');
fieldTypeMap.set('dimension','Integer');
returnfieldTypeMap;
}
getClassName(){
return't_form';
}
getPrimaryKeyList(){
letprimaryKeyList=[];
primaryKeyList.push('formId');
returnprimaryKeyList;
}
getIndexList(){
letindexList=[];
returnindexList;
}
getEncryptedFieldList(){
letencryptedFieldList=[];
returnencryptedFieldList;
}
//setandget
setFormId(formId){this.formId=formId;}
getFormId(){returnthis.formId;}
setFormName(formName){this.formName=formName;}
getFormName(){returnthis.formName;}
setDimension(dimension){this.dimension=dimension;}
getDimension(){returnthis.dimension;}
}
module.exports={t_form}
CloudDBZoneWrapper 操作云數據庫,這里主要列舉構造函數和增加方法內容:
import*asclouddbfrom'@agconnect/database-server';
import{t_formasFormBean}from'./models/t_form';
import*asagconnectfrom'@agconnect/common-server';
constZONE_NAME="widgetCard";
exportclassCloudDBZoneWrapper{
logger;
cloudDbZone;
constructor(credential,logger){
this.logger=logger;
try{
//初始化AGCClient
letagcClient;
try{
agcClient=agconnect.AGCClient.getInstance();
}catch{
agconnect.AGCClient.initialize(credential);
agcClient=agconnect.AGCClient.getInstance();
}
//初始化AGConnectCloudDB實例
letcloudDbInstance;
try{
cloudDbInstance=clouddb.AGConnectCloudDB.getInstance(agcClient);
}catch{
clouddb.AGConnectCloudDB.initialize(agcClient);
cloudDbInstance=clouddb.AGConnectCloudDB.getInstance(agcClient);
}
//創建CloudDBZoneConfig配置對象,并設置云側CloudDBzone名稱,打開CloudDBzone實例
constcloudDBZoneConfig=newclouddb.CloudDBZoneConfig(ZONE_NAME);
this.cloudDbZone=cloudDbInstance.openCloudDBZone(cloudDBZoneConfig);
}catch(err){
logger.error("xx[form-func]CloudDBZoneWrapperinitCloudDBZoneWrappererror:"+err);
}
}
asyncinsert(addForm){
if(!this.cloudDbZone){
this.logger.error("xx[form-func]CloudDBZoneWrapper->insertCloudDBClientisnull,tryre-initializeit");
}
try{
letres=awaitthis.cloudDbZone.executeUpsert(addForm);
this.logger.info("xx[form-func]CloudDBZoneWrapper->insertInsert"+res+"recordssuccess");
}catch(error){
this.logger.error("xx[form-func]CloudDBZoneWrapper->insertexecuteInsertaddressRecordsfailed"+error);
}
}
}
新增卡片函數 form-insert,關鍵代碼如下:
import{CloudDBZoneWrapper}from'../clouddb/CloudDBZoneWrapper.js';
import*asUtilsfrom'../utils/Utils.js';
exportconstmyHandler=asyncfunction(event,context,callback,logger){
constcredential=Utils.getCredential(context,logger);
try{
constcloudDBZoneWrapper=newCloudDBZoneWrapper(credential,logger);
letformObj=cloudDBZoneWrapper.getForm(event);
awaitcloudDBZoneWrapper.insert(formObj);
callback({
ret:{code:0,desc:"SUCCESS"},
});
}catch(err){
logger.error("xx[form-func]insertfuncerror:"+err.message+"stack:"+err.stack);
callback({
ret:{code:-1,desc:"ERROR"},
});
}
};
卡片云函數主入口,關鍵代碼如下:
letmyHandler=asyncfunction(event,context,callback,logger){
letoperation;
letparams;
logger.info("xxenterformfuncwithoperation"+event.operation);
operation=event.body?JSON.parse(event.body).operation:event.operation;
params=event.body?JSON.parse(event.body).params:event.params;
switch(operation){
case"query":
query.myHandler(params,context,callback,logger);
break;
case"queryById":
queryById.myHandler(params,context,callback,logger);
break;
case"insert":
insert.myHandler(params,context,callback,logger);
break;
case"update":
update.myHandler(params,context,callback,logger);
break;
case"delete":
deleteByObj.myHandler(params,context,callback,logger);
break;
default:
callback({
ret:{code:-1,desc:"nosuchfunction"},
});
}
};
module.exports.myHandler=myHandler;
②成績云函數創建
展開 CloudProgram→cloudfunctions 右擊 cloudfunctions 目錄,創建→Cloud Function 輸入 Cloud Function Name 為 score-func,點擊確認,。成績云函數里包含了增刪改查操作,所以在 score-func 下,創建不同的文件夾來區分。目錄結構如下:
成績表云數據庫操作與卡片操作一樣,這里就不在重復了,可以參考一下上面卡片操作方法就可以。云函數本地與遠程調試
①Run 模式啟動調試
右擊“cloudfunctions”目錄,選擇“Run Cloud Functions”。查看“Run”面板。如果出現“Cloud Functions loaded successfully”,表示所有函數已成功加載到本地運行的 HTTP Server 中,并生成對應的 POST URL。在菜單欄選擇“Tools > CloudDev > Cloud Functions Requestor”,使用 Cloud Functions Requestor 觸發函數調用。在彈出的“Cloud Functions Requestor”面板,填寫觸發事件參數。點擊“Save”,可保存當前觸發事件。②Debug 模式啟動調試
右擊“cloudfunctions”目錄,選擇“Run Cloud Functions”。查看 Console 面板。如果出現“Cloud Functions loaded successfully”,表示函數成功加載到本地運行的 HTTP Server 中,并生成對應的 POST URL。如需設置斷點調試,在函數代碼中選定要設置斷點的有效代碼行,在行號后單擊鼠標左鍵設置斷點,設置斷點后,調試能夠在斷點處中斷,并高亮顯示該行。在菜單欄選擇“Tools > CloudDev > Cloud Functions Requestor”,使用 Cloud Functions Requestor 觸發函數調用。在彈出的“Cloud Functions Requestor”面板,填寫觸發事件參數。點擊“Save”,可保存當前觸發事件。③自定義 Run/Debug 配置
在菜單欄選擇“Run > Edit Configurations”。在“Run/Debug Configurations”窗口,點擊+,選擇“Cloud Functions”,新增一個 Run/Debug 配置。自定義 Run/Debug 配置,完成后點擊“OK”。
· Name:Run/Debug配置的名稱,如“functions-custom1”。
· Server Port:HTTP服務端監聽端口。默認為“18090”,自定義端口號建議大于1024。勾選“Autoincrement”表示如當前端口被占用則端口號自動加“1”。
· Environment variables:函數運行的環境變量,為key-value形式。
點擊“Edit environment variables”按鈕,在“Environment Variables”彈窗中點擊“+”添加一個環境變量,然后點擊“OK”。添加成功后,您便可以將變量配置信息傳入到函數執行環境中,用于函數運行時讀取。
選擇剛剛自定義的 Run/Debug 配置,分別點擊 Run 或 Debug。后續調試步驟與默認配置下的調試步驟一致,請分別參見Run 模式啟動調試或Debug 模式啟動調試。④測試
實現云函數調用云數據庫,需要您先部署云工程,云端才會有相關數據及環境變量。同時,云函數為訪問云數據庫使用了“PROJECT_CREDENTIAL”環境變量,部署函數到 AGC 云端時,云端會自動配置好“PROJECT_CREDENTIAL”以運行環境變量。但在本地調試函數時,需要您手動將“PROJECT_CREDENTIAL”環境變量添加到 Run/Debug 配置中。否則,函數調試代碼執行會因獲取不到“PROJECT_CREDENTIAL”環境變量而中斷。
從 AGC 獲取的“PROJECT_CREDENTIAL”環境變量添加到調試配置中。您也可以添加您需要的其他環境變量。
添加完環境變量后,啟動函數,再點擊 Trigger,就可以看到成功返回數據了。
代碼講解
①云函數調用公共類
DatabaseUtils.ets 云函數操作類部分代碼如下:
exportclassDatabaseUtils{
asynccallWithParams(context,trigger,operation,params){
awaitgetAGConnect(context);
letbody={
"operation":operation,
"params":params
}
try{
letfunctionCallable=agconnect.function().wrap(trigger);
letfunctionResult=awaitfunctionCallable.call(body);
returnfunctionResult.getValue();
//returnfunctionResult.getValue().result;
}
catch(err){
return{
"ret":{"code":-1,"desc":"ERROR"}
}
}
}
asyncinvoke(context:any,trigger?:string,operation?:string,params?:object){
console.info(CommonConstants.DATABASE_TAG,'xxinvokeparams:'+JSON.stringify(params))
returnawaitthis.callWithParams(context,trigger,operation,params);
}
/**
*插入卡片數據。
*
*@param{Form}Form表單實體。
*@param{DataRdb.RdbStore}RDB存儲RDB數據庫。
*@return返回操作信息。
*/
asyncinsertForm(context:any,form:Form){
letres=awaitthis.invoke(context,Triggers.FormFunc,RequestType.Insert,form);
console.info(CommonConstants.DATABASE_TAG,'xxinsertFormresult:'+JSON.stringify(res));
}
......
}
②卡片 Ability 調用公共類
EntryFormAbility.ets 卡片生命周期代碼如下:
onAddForm(want){
//獲取卡片ID:ohos.extra.param.key.form_identity
letformId:string=want.parameters[CommonConstants.FORM_PARAM_IDENTITY_KEY]asstring;
//獲取卡片名稱:ohos.extra.param.key.form_name
letformName:string=want.parameters[CommonConstants.FORM_PARAM_NAME_KEY]asstring;
//獲取卡片規格:ohos.extra.param.key.form_dimension
letdimensionFlag:number=want.parameters[CommonConstants.FORM_PARAM_DIMENSION_KEY]asnumber;
//卡片信息
letform:Form=newForm();
form.formId=formId;
form.formName=formName;
form.dimension=dimensionFlag;
//保存卡片信息到數據庫
DatabaseUtils.insertForm(this.context,form);
//獲取最優成績
getScoreById(this.context,dimensionFlag,formId);
//每五分鐘刷新一次
formProvider.setFormNextRefreshTime(formId,CommonConstants.FORM_NEXT_REFRESH_TIME,(error,data)=>{
if(error){
console.error(CommonConstants.ENTRY_FORM_ABILITY_TAG,'xx onAddForm 更新卡片失敗:'+JSON.stringify(error))
}else{
console.info(CommonConstants.ENTRY_FORM_ABILITY_TAG,'xxonAddForm更新卡片成功')
}
});
//返回初始化卡片數據
letformData:FormData=newFormData();
formData.formId=formId;
formData.bestScore=0;
formData.matrixNum='1x1';
formData.totalBestScore=0;
returnformBindingData.createFormBindingData(formData);
}
③主界面調用公共類
@Entry
@Component
structIndex{
@StatescoreDataList:Array=[]
aboutToAppear(){
//請求通知欄權限
this.requestNotification();
//更新卡片信息
DatabaseUtils.updateForms(getContext(this));
//獲取成績歷史記錄
this.getScoreListData()
}
onPageShow(){
//更新卡片信息
DatabaseUtils.updateForms(getContext(this));
//獲取成績歷史記錄
this.getScoreListData()
}
//獲取成績歷史數據
getScoreListData(){
DatabaseUtils.getScoreListData(getContext(this))
.then((res)=>{
this.scoreDataList=res;
//發送通知
NotificationUtils.sendNotifications(this.scoreDataList[0].totalBestScore);
}).catch((error)=>{
console.error(CommonConstants.MAIN_PAGE_TAG,'xxaboutToAppearoronPageShowgetScoreListDataerror'+JSON.stringify(error));
});
}
build(){...}
}
總結
通過把之前小游戲元服務-關系型數據庫修改為使用 Serverless 云函數、云數據庫,學習到不少知識,開始時不懂得怎么使用云函數調用云數據庫,一邊參考官方商城模板,一邊測試,到使用到這個小游戲上,。總結這個項目用到以下知識點:- 使用 notification 發布通知。
- 使用端云一體化開發、開發云函數、開發云數據庫。
- 使用 FormExtensionAbility 創建、更新、刪除元服務卡片。
備注:資源文件是我在學習云函數調用云數據庫寫的一個簡單實例,有云函數調用云數據庫需求的小伙伴可以下載下來參考一下。
-
數據庫
+關注
關注
7文章
3763瀏覽量
64274 -
模板
+關注
關注
0文章
108瀏覽量
20554 -
HarmonyOS
+關注
關注
79文章
1967瀏覽量
30013
原文標題:HarmonyOS云開發:舒爾特方格游戲
文章出處:【微信號:gh_834c4b3d87fe,微信公眾號:OpenHarmony技術社區】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論