简介
Demo基于Open Harmony系统使用ETS语言进行编写,本Demo主要通过设备认证、分布式拉起、分布式数据管理等功能来实现。
应用效果
开发步骤
1.新建Openharmony ETS工程
在DevEco Studio中点击File -> New Project ->[Standard]Empty Ability->Next,Language 选择ETS语言,最后点击Finish即创建成功。
2.界面代码编写
首页界面
build() {Flex({ direction: FlexDirection.Column}) {//发现设备Button('发现设备', { type: ButtonType.Normal, stateEffect: true }).borderRadius(8).backgroundColor(0x317aff).width(90).onClick(() =>{this.fun()})//设备认证Button('authDevice', { type: ButtonType.Normal, stateEffect: true }).borderRadius(8).backgroundColor(0x317aff).width(90).onClick(() =>{this.authDevice()})// 拉起应用Button('拉起应用', { type: ButtonType.Normal, stateEffect: true }).borderRadius(8).backgroundColor(0x317aff).width(90).onClick(() =>{this.startAb()})Stack({alignContent:Alignment.TopEnd}){Text('家庭账本').fontSize(20).fontWeight(FontWeight.Bold).width('100%').margin({left:12}).onClick(() =>{// routePage()this.fun()})Image("/picture/add.png").width(40).height(40).align(Alignment.Start).margin({right:12}).onClick(() =>{routePage()})}.width(350).height(60).margin({top:10,bottom:10})Flex({direction: FlexDirection.Column, alignItems:ItemAlign.Start,}){Text("2022年12月").fontSize(20).fontColor(Color.White)Text("结余").fontSize(20).fontColor(Color.White).margin({top:30}).align(Alignment.Start)Text("总支出0|总收入0").fontSize(16).fontColor(Color.White).margin({top:10}).align(Alignment.Start)}.backgroundColor("#665A5A").height(230).layoutWeight(1).padding(10).onClick(() =>{routePage()})Tabs() {TabContent() {ProjectList()}.tabBar("项目")TabContent() {Statistics()}.tabBar("统计")}}.width('100%').height('100%').padding({left:12,right:12})}
底部TabContent 项目模块
@Component
struct ProjectList {remoteDataManager = new RemoteDataManager()@State ProjectData: Array<any> = []TestData:any[] = []TestKvData: Array<any> = []kvManager = nullkvStore = nullSTORE_ID = 'store_accountbook'aboutToAppear(){try {const config = {userInfo: {userId: '0',userType: 0},bundleName: 'com.example.accountbookets'}factory.createKVManager(config).then((manager) => {this.kvManager = managerlet options ={createIfMissing: true,encrypt: false,backup: false,autoSync: true,kvStoreType: 1,securityLevel: 3}this.kvManager.getKVStore(this.STORE_ID, options).then((store) => {this.kvStore = storethis.kvStore.get("key2").then((data) => {this.ProjectData = JSON.parse(data)})}).catch((err) => {})}).catch((err) => {})} catch (e) {}}@Builder ProjectItem(image, name, des,time,money) {Flex({ direction: FlexDirection.Row,alignItems: ItemAlign.Center }){Image($r("app.media.icon1")).width(30).height(30)Column() {Text(name).fontSize(16).fontColor(Color.Black)Text('11:20').fontSize(16).fontColor(Color.Gray)}.alignItems(HorizontalAlign.Start).margin({left:15})Text('HUAWEI').fontSize(12).fontColor(Color.Black).margin({left:20})Text(des).fontSize(14).fontColor(Color.Gray).margin({left:15})Column() {Text('-100').fontSize(16).fontColor(Color.Black)Text(time).fontSize(16).fontColor(Color.Gray)}.alignItems(HorizontalAlign.Start).margin({left:20})}.width(400).height(50).margin({top:10})}build() {List() {ForEach(this.ProjectData, (item) => {ListItem() {this.ProjectItem(item.image, item.name, item.des,item.time,item.money)}.onClick(() => {})}, (item) => JSON.stringify(item)) {}}}
}
底部TabContent 统计模块
@Component
struct Statistics{build(){Flex({ direction: FlexDirection.Row}){Tabs() {TabContent() {PayList()}.tabBar("支出分类")TabContent() {}.tabBar("成员分类")}}}
}
统计模块里面的TabContent
@Component
struct PayList {private PayData: PayBean[] = initializeOnStartup()@Builder PayItem(previewUrl, title, describe) {Flex({ direction: FlexDirection.Row,alignItems: ItemAlign.Center }){Image(previewUrl).width(30).height(30)Text(title).fontSize(16).fontColor(Color.Black).margin({left:8})Text('100%').fontSize(12).fontColor(Color.Black).margin({left:8})Progress({ value: 20, total: 150, style: ProgressStyle.Linear }).color(Color.Red).value(150).width(200)Text('-100').fontSize(14).fontColor(Color.Gray).margin({left:8})}.width(400).height(50).margin({top:10})}build() {List() {ForEach(this.PayData, (item) => {ListItem() {this.PayItem(item.image, item.name, item.des)}.onClick(() => {console.info("点击我")router.push({uri: "pages/VideoPlayer",})})}, (item) => JSON.stringify(item)) {}}}
}
2) add.ets页面
build() {Flex({ direction: FlexDirection.Column,alignItems: ItemAlign.Center}) {Flex({ direction: FlexDirection.Row,alignItems: ItemAlign.Center}){Image("/picture/icon_back.png").width(35).height(35).onClick(() =>{router.push({uri: "pages/index",})})Text("加一笔").fontSize(20).fontWeight(FontWeight.Bold).margin({left:20})}.margin({top:10}).padding({left:20}).height(100).width(500)Stack({alignContent: Alignment.TopStart}){Tabs() {TabContent() {pay({payTime:$strTime,payRemark:$strRemark,payType:$strType})}.tabBar("支出")TabContent() {Income()}.tabBar("收入")}.height(450)}.width(500).height(500)Flex({direction: FlexDirection.Row,alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center}){Text("输入金额").fontColor(Color.Black).fontSize(20).margin({right:15}).width(100)TextInput({ placeholder: '100', text:this.strMoney }).type(InputType.Normal).placeholderColor(Color.Gray).placeholderFont({ size: 20, weight: 2}).enterKeyType(EnterKeyType.Search).caretColor(Color.Green).width(250).height(40).borderRadius('20px')}.width(400).height(50)Text('保存').fontColor(Color.White).fontSize(20).margin({top:20}).textAlign(TextAlign.Center).width(380).height(80).backgroundColor("#FE4F16").onClick(() =>{TestData.push({image:"/picture/icon1.png",title:'canyin',des:'ceshi',time:'2021',money:'50'})if (AppStorage.Get("key1") == null) {AppStorage.SetAndLink("key1", TestData)this.remoteDataManager.dataChange("key2", JSON.stringify(TestData))}else{this.TestStorageData = AppStorage.Get("key1")//
// this.TestStorageData.push({image:"/picture/icon1.png",title:'canyin',des:'beizhu',time:'2021',money:'50'})//具体代码this.TestStorageData.push({image:"/picture/icon1.png",title:this.strType,des:this.strRemark,time:this.strTime,money:this.strMoney})AppStorage.SetAndLink("key1", this.TestStorageData)let str = JSON.stringify(this.TestStorageData)this.TestKvData = JSON.parse(str)this.remoteDataManager.dataChange("key2", JSON.stringify(this.TestKvData))}router.push({uri: "pages/index",})})}.width('100%').height('100%')}
add页面支出模块
@Component
struct pay{@Link payTime:string@Link payRemark:string@Link payType:string@State private index:number = 0@State strType:string = "canyin"@State AccountData: Array<any> = [{ previewUrl: "/picture/icon1.png", title: "canyin" ,number:0},{ previewUrl: "/picture/icon2_2.png", title: "gouwu" ,number:1},{ previewUrl: "/picture/icon3_3.png", title: "jiaotong" ,number:2},{ previewUrl: "/picture/icon4_4.png", title: "fuwu" ,number:3},{ previewUrl: "/picture/icon5_5.png", title: "jiaoyu" ,number:4},{ previewUrl: "/picture/icon6_6.png", title: "yundong" ,number:5},{ previewUrl: "/picture/icon7_7.png", title: "luxing" ,number:6},{ previewUrl: "/picture/icon8_8.png", title: "yiliao" ,number:7},
// { previewUrl: "/picture/icon9_9.png", title: "生活" ,number:9},
// { previewUrl: "/picture/icon10_10.png", title: "宠物" ,number:10},]@Builder ProItem(previewUrl, title,number) {Stack() {Flex({direction: FlexDirection.Column}) {if (this.index == number) {if (number == 0) {Image("/picture/icon1.png").width(60).height(60)}else if (number == 1) {Image("/picture/icon2.png").width(60).height(60)}else if (number == 2) {Image("/picture/icon3.png").width(60).height(60)}else if (number == 3) {Image("/picture/icon4.png").width(60).height(60)}else if (number == 4) {Image("/picture/icon5.png").width(60).height(60)}else if (number == 5) {Image("/picture/icon6.png").width(60).height(60)}else if (number == 6) {Image("/picture/icon7.png").width(60).height(60)}else if (number == 7) {Image("/picture/icon8.png").width(60).height(60)}else if (number == 8) {Image("/picture/icon9.png").width(60).height(60)}else if (number == 9) {Image("/picture/icon10.png").width(60).height(60)}}else{if (number == 0) {Image("/picture/icon1_1.png").width(60).height(60)}else{Image(previewUrl).width(60).height(60)}}Column() {Text(title).fontSize(16).fontColor(Color.Black)}.alignItems(HorizontalAlign.Center)}}.height(100).width(100).margin({bottom: 16})}build(){Flex({direction: FlexDirection.Column}){Grid(){ForEach(this.AccountData, (item) => {GridItem() {this.ProItem(item.previewUrl, item.title,item.number)}.onClick(() => {console.info("点击我")this.index = item.numberthis.payType = this.AccountData[this.index].title})}, (item) => JSON.stringify(item)) {}}.rowsTemplate('1fr 1fr').columnsTemplate('1fr 1fr 1fr 1fr').columnsGap(8).rowsGap(8).height(200)
// Time()
// Remark()// ******************时间**********************Flex({direction: FlexDirection.Row,alignItems: ItemAlign.Center}){Text("时间").fontColor(Color.Black).fontSize(20).margin({right:15}).width(70)TextInput({ placeholder: '输入收支时间', text: this.payTime }).type(InputType.Normal).placeholderColor(Color.Gray).placeholderFont({ size: 20, weight: 2}).enterKeyType(EnterKeyType.Search).caretColor(Color.Green).width(300).height(40).borderRadius('20px').backgroundColor(Color.White).onChange((value: string) => {this.payTime = value})}.margin({top:20,left:15}).width(200)//*******************备注********************Flex({direction: FlexDirection.Row,alignItems: ItemAlign.Center}){Text("备注").fontColor(Color.Black).fontSize(20).margin({right:15}).width(70)TextInput({ placeholder: '输入说明', text: this.payRemark }).type(InputType.Normal).placeholderColor(Color.Gray).placeholderFont({ size: 20, weight: 2}).enterKeyType(EnterKeyType.Search).caretColor(Color.Green)// .layoutWeight(8).height(40).width(300).borderRadius('20px').backgroundColor(Color.White).onChange((value: string) => {this.payRemark = value})}.margin({top:20,left:15}).width(50).height(50)}.height('100%').layoutWeight(1)}
}
收入模块代码
@Component
struct Income{build(){Flex({direction: FlexDirection.Column}){Time()Remark()}}
}
时间模块
@Component
struct Time{@State inputTime:string = ''build(){Flex({direction: FlexDirection.Row,alignItems: ItemAlign.Center}){Text("时间").fontColor(Color.Black).fontSize(20).margin({right:15}).width(70)TextInput({ placeholder: '2021', text: this.inputTime }).type(InputType.Normal).placeholderColor(Color.Gray).placeholderFont({ size: 20, weight: 2}).enterKeyType(EnterKeyType.Search).caretColor(Color.Green).width(300).height(40).borderRadius('20px').backgroundColor(Color.White)}.margin({top:20,left:15}).width(200)}
}
备注模块
@Component
struct Remark{@State inputRemark:string = ''build(){Flex({direction: FlexDirection.Row,alignItems: ItemAlign.Center}){Text("备注").fontColor(Color.Black).fontSize(20).margin({right:15}).width(70)TextInput({ placeholder: 'ceshe', text: this.inputRemark }).type(InputType.Normal).placeholderColor(Color.Gray).placeholderFont({ size: 20, weight: 2}).enterKeyType(EnterKeyType.Search).caretColor(Color.Green)
// .layoutWeight(8).height(40).width(300).borderRadius('20px').backgroundColor(Color.White)}.margin({top:20,left:15}).width(50).height(50)}
}
3.设备认证
设备认证是依赖 DeviceManager 组件来实现的,详细代码参考源码RemoteDeviceModel.ets
1.创建DeviceManager实例
registerDeviceListCallback(callback) {if (typeof (this.#deviceManager) === 'undefined') {deviceManager.createDeviceManager('com.example.tictactoegame', (error, value) => {if (error) returnthis.#deviceManager = value;this.registerDeviceListCallback_(callback);});} else {this.registerDeviceListCallback_(callback);}}
2.查询可信设备列表
var list = this.#deviceManager.getTrustedDeviceListSync();if (typeof (list) != 'undefined' && typeof (list.length) != 'undefined') {this.deviceList = list;}
3.注册设备上下线监听
this.#deviceManager.on('deviceStateChange', (data) => {switch (data.action) {case 0:this.deviceList[this.deviceList.length] = data.device;this.callback();if (this.authCallback != null) {this.authCallback();this.authCallback = null;}break;case 2:if (this.deviceList.length > 0) {for (var i = 0; i < this.deviceList.length; i++) {if (this.deviceList[i].deviceId === data.device.deviceId) {this.deviceList[i] = data.device;break;}}}this.callback();break;case 1:if (this.deviceList.length > 0) {var list = [];for (var i = 0; i < this.deviceList.length; i++) {if (this.deviceList[i].deviceId != data.device.deviceId) {list[i] = data.device;}}this.deviceList = list;}this.callback();break;default:break;}});
4.设备发现
this.#deviceManager.on('deviceFound', (data) => {for (let i = 0; i < this.discoverList.length; i++) {if (that.discoverList[i].deviceId === data.device.deviceId) {return;}}this.discoverList[this.discoverList.length] = data.device;this.callback();});
5.设备认证
authDevice(deviceInfo, callback){let extraInfo = {"targetPkgName": 'com.example.tictactoegame',"appName": 'com.example.tictactoegame',"appDescription": 'com.example.tictactoegame',"business": '0'};let authParam = {"authType": 1,"appIcon": '',"appThumbnail": '',"extraInfo": extraInfo};this.#deviceManager.authenticateDevice(deviceInfo, authParam, (err, data) => {if (err) {this.authCallback = null;} else {this.authCallback = callback;}});}
4.数据管理
分布式数据管理
依赖@ohos.data.distributedData模块实现,详细参考源码RemoteDataManager.ets
1.导入该模块
import factory from '@ohos.data.distributedData';
2.创建KVManager实例,用于管理数据库对象
registerDataListCallback(callback) {let that = thisif (this.kvManager == null) {try {const config = {userInfo: {userId: '0',userType: 0},bundleName: 'com.example.tictactoegame'}factory.createKVManager(config).then((manager) => {that.kvManager = managerthat.registerDataListCallback_(callback)}).catch((err) => {})} catch (e) {}} else {this.registerDataListCallback_(callback)}}
3.创建并获取KVStore数据库
registerDataListCallback_(callback) {let that = thisif (that.kvManager == null) {callback()return}if (that.kvStore == null) {try {let options ={createIfMissing: true,encrypt: false,backup: false,autoSync: true,kvStoreType: 1,securityLevel: 3}this.kvManager.getKVStore(this.STORE_ID, options).then((store) => {that.kvStore = storethat._registerDataListCallback_(callback)}).catch((err) => {})} catch (e) {}} else {this._registerDataListCallback_(callback)}}
4.订阅指定类型的数据变更通知
_registerDataListCallback_(callback) {let that = thisif (that.kvManager == null) {callback()return}this.kvStore.on('dataChange', 1, function(data) {if (data) {that.arr = data.updateEntriescallback()}})}
5.添加指定类型键值对到数据库
startAbilityContinuation(deviceId) {let wantValue = {bundleName: 'com.example.tictactoegame',abilityName: 'com.example.tictactoegame.MainAbility',deviceId: deviceId,parameters: {uri: 'pages/Fight'}};featureAbility.startAbility({ want: wantValue }).then(() => {router.replace({ uri: 'pages/Fight' })});}
5.远程拉起设备app
使用 FeatureAbility 模块的startAbility接口拉起远程设备app
startAbilityContinuation(deviceId) {let wantValue = {bundleName: 'com.example.tictactoegame',abilityName: 'com.example.tictactoegame.MainAbility',deviceId: deviceId,parameters: {uri: 'pages/Fight'}};featureAbility.startAbility({ want: wantValue }).then(() => {router.replace({ uri: 'pages/Fight' })});}
6.添加数据
新建一个账单数据 添加到分布式数据
this.remoteDataManager.dataChange("key2", JSON.stringify(this.TestKvData))
在另一台设备监听并获取显示该条数据
private onPageShow() {this.remoteDataManager.registerDataListCallback(() => {let arr = this.remoteDataManager.arr[0]this.strTest = arr.value.valuethis.ProjectData = JSON.parse(this.strTest)}
为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05
《鸿蒙开发学习手册》:https://qr21.cn/FV7h05
入门必看:https://qr21.cn/FV7h05
1. 应用开发导读(ArkTS)
2. ……
HarmonyOS 概念:https://qr21.cn/FV7h05
- 系统定义
- 技术架构
- 技术特性
- 系统安全
如何快速入门:https://qr21.cn/FV7h05
1. 基本概念
2. 构建第一个ArkTS应用
3. ……
开发基础知识:https://qr21.cn/FV7h05
1. 应用基础知识
2. 配置文件
3. 应用数据管理
4. 应用安全管理
5. 应用隐私保护
6. 三方应用调用管控机制
7. 资源分类与访问
8. 学习ArkTS语言
9. ……
基于ArkTS 开发:https://qr21.cn/FV7h05
1. Ability开发
2. UI开发
3. 公共事件与通知
4. 窗口管理
5. 媒体
6. 安全
7. 网络与链接
8. 电话服务
9. 数据管理
10. 后台任务(Background Task)管理
11. 设备管理
12. 设备使用信息统计
13. DFX
14. 国际化开发
15. 折叠屏系列
16. ……