鸿蒙开发【记事APP】实战案例

打印 上一主题 下一主题

主题 1007|帖子 1007|积分 3031

1 简介

生活中的零碎信息太容易忘记,「记事APP」作为记录噜苏的小帮助,时刻记录用户关心的内容,分类整理,高效编辑,快捷分享。Less is More,借助HarmonyOS NEXT丰富的原生能力,一步操纵完成各种所想,抓住每一刻灵感。


  • 目标用户:学生、记者、产物经理、艺术创作者
本篇将介绍如何利用HarmonyOS NEXT原生能力开发灵感速记APP。效果为:


  • 化繁为简,便捷高效

    • 聊天式一键添加备忘、关联日程、强提示消息、私密消息等轻量条记。
    • 可分类、搜索、分享、删除等管理记录的每条内容。


  • 统一生态,有趣好用:

    • 可共享消息到生态互联设备(灵动看板)。
    • 支持多端结构。


2 环境搭建

我们起首需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。
软件要求



  • DevEco Studio版本:DevEco Studio NEXT Developer Preview2及以上。
  • HarmonyOS SDK版本:HarmonyOS NEXT Developer Preview2 SDK及以上。

硬件要求



  • 设备范例:华为手机。
  • HarmonyOS体系:HarmonyOS NEXT Developer Preview2及以上。
环境搭建


  • 安装DevEco Studio,详情请参考[下载]和[安装软件]。
  • 设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常利用,详情请参考[设置开发环境]。
  • 开发者可以参考以下链接,完成设备调试的相关设置:

    • [利用真机进行调试]

3 代码结构解读

本篇文档只对核心代码进行讲解,对于完备代码,开源后提供下载链接。
  1. .
  2. |-- common
  3. |   |-- BreakPointSystem.ets //断点-多端布局
  4. |   |-- CommonConstant.ets   //常量
  5. |   |-- DateUtil.ets         //时间日期工具
  6. |   |-- InspiDataModule.ets  //灵感数据模型
  7. |   |-- Logger.ets           //日志工具
  8. |   |-- calendar.ets         //日历日程工具
  9. |   |-- database             //RDB数据库,实现持久化存储
  10. |   |   |-- InspirationTable.ets
  11. |   |   |-- RDB.ets
  12. |   |   `-- inspirationData.ets
  13. |   |-- messageManager       //后台提醒、日程消息
  14. |   |   |-- BackgroundReminder.ets
  15. |   |   `-- CalenderMeaasge.ets
  16. |   |-- microphone           //语音输入
  17. |   |   `-- Recorder.ets
  18. |   `-- shareTool.ets        //分享工具
  19. |-- entryability
  20. |   `-- EntryAbility.ts   
  21. |-- entryformability
  22. |   `-- EntryFormAbility.ets
  23. |-- pages
  24. |   |-- Index.ets            //入口页面
  25. |   `-- SettingPage.ets      //设置页面
  26. |-- subview                    
  27. |   |-- AddPanel.ets            //添加笔记组件
  28. |   |-- InspiComponent.ets      //笔记列表组件
  29. |   |-- InspirationItemView.ets //单条笔记组件
  30. |   |-- InspirationTotalView.ets//笔记分类视图
  31. `-- widget22
  32.     `-- pages
  33.         `-- Widget22Card.ets    //2*2桌面卡片
  34. 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.
复制代码
4 构建应用主界面

灵感速记应用步伐遵循多端、极简页面、功能一触即达的计划理念。以手机端为例,如下图所示,首页结构了95%的功能,自下而上依次是添加和共享条记、条记查看、管理条记的三大功能区。

在主页面中利用[断点])来分配结构,比方在手机端首页只展示消息列表视图,在折叠屏或平板上屏幕右侧新增了分类视图。整体的结构框架如下:
  1. build() {
  2.     Stack() {
  3.       Row() {
  4.         Column() {
  5.           // menu
  6.           Row(){  ... }
  7.           // inspiration内容
  8.           // 配合List组件,循环渲染,可滚动内容
  9.             List({ space: 6, scroller: this.listScroller }) {
  10.               ForEach(this.Inspirations : this.searchInspirations,
  11.                 (item: InspirationData, index: number) => {
  12.                   ListItem() {
  13.                     InspirationItemView({
  14.                       InspiItem: item,
  15.                      ...
  16.                  })
  17.             }
  18.       
  19.           if (!this.isSearchPageShow && !this.isInsert && !this.isEditMode) {
  20.             // 添加新内容+按钮
  21.             Image($r('app.media.add_filled'))
  22.             // 共享到灵动看板桌面 弹窗
  23.             Image($r('app.media.panel_icon'))
  24.               .onClick(() => {
  25.                 this.isShowDeskPanel = true
  26.               })
  27.         }
  28.         .width(this.MycurrentBreakpoint != 'sm' ? '50%' : '100%')
  29.           // 断点来实现多端布局
  30.         if (this.MycurrentBreakpoint != 'sm') {
  31.           Column() {
  32.             // 内容按颜色整理的详情页
  33.             InspirationTotalView({
  34.               Inspirations: this.Inspirations
  35.             })
  36.           }
  37.           .width('50%')
  38.           .height('100%')
  39.         }
  40.       }.width('100%').height('100%')
  41.     }
  42.   }
  43. 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.
复制代码
5 条记数据管理

数据界说

应用开发与数据结构痛痒相关,在进行其他功能开发前,规划如下灵感速记的数据,主要包罗条记文本内容、记录时间、类别、完成环境等。
  1. export default class InspirationData {
  2.   id: number = -1;
  3.   inspirationName: string = '';
  4.   updateTime: string = '';
  5.   progressValue: number = 0;
  6.   inspirationType:number = InspirationType.CREATE_IDEA;
  7.   inspirationColor:string = CommonConstants.CREATE_COLOR;
  8.   inspirationDone: boolean = false;
  9.   inspirationAlarm: boolean  = false;
  10.   inspirationPic: string = '';
  11.   inspirationPicIndex: number = 0;
  12.   inspirationIcon: string ='app.media.create_idea_filled';
  13.   constructor() {
  14.     ...
  15.   }
  16. }
  17. 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.
复制代码
数据恒久化

用户记录的条记盼望能恒久化保存,便于用户随时查找翻阅条记。
HarmonyOS NEXT中的ArkData ([方舟数据管理])为开发者提供数据存储、数据管理和数据同步能力。此中,数据存储提供通用数据恒久化能力,根据数据特点,分为用户首选项、键值型数据库和关系型数据库。灵感速记的数据较为复杂,选择[关系型数据库](RDB)进行存储。


  • 起首获取一个RdbStore,此中包罗建库、建表、升降级等操纵。
  1. import { relationalStore } from '@kit.ArkData';
  2. export default class Rdb {
  3.   private rdbStore: relationalStore.RdbStore | null = null;
  4.   private tableName: string;
  5.   private sqlCreateTable: string;
  6.   private columns: Array<string>;
  7.   constructor(tableName: string, sqlCreateTable: string, columns: Array<string>) {
  8.     this.tableName = tableName;
  9.     this.sqlCreateTable = sqlCreateTable;
  10.     this.columns = columns;
  11.   }
  12.   getRdbStore(callback: Function = () => {
  13.   }) {
  14.     let context: Context = getContext(this) as Context;
  15.     relationalStore.getRdbStore( AppStorage.get('context'), CommonConstants.STORE_CONFIG, (err, rdb) => {
  16.      ...
  17.       this.rdbStore = rdb;
  18.       this.rdbStore.executeSql(this.sqlCreateTable);
  19.     });
  20.   }
  21.   insertData(data: relationalStore.ValuesBucket, callback: Function = () => {
  22.   }) {
  23.   
  24.     let resFlag: boolean = false;
  25.     const valueBucket: relationalStore.ValuesBucket = data;
  26.     if (this.rdbStore) {
  27.       this.rdbStore.insert(this.tableName, valueBucket, (err, ret) => {
  28.         ...
  29.       });
  30.     }
  31.   }
  32.   deleteData(predicates: relationalStore.RdbPredicates, callback: Function = () => {
  33.   }) {
  34.     let resFlag: boolean = false;
  35.     if (this.rdbStore) {
  36.       this.rdbStore.delete(predicates, (err, ret) => {
  37. ...
  38.       });
  39.     }
  40.   }
  41.   updateData(predicates: relationalStore.RdbPredicates, data: relationalStore.ValuesBucket, callback: Function = () => {
  42.   }) {
  43.    
  44.     let resFlag: boolean = false;
  45.     const valueBucket: relationalStore.ValuesBucket = data;
  46.     if (this.rdbStore) {
  47.       this.rdbStore.update(valueBucket, predicates, (err, ret) => {
  48.        ...
  49.       });
  50.     }
  51.   }
  52.   query(predicates: relationalStore.RdbPredicates, callback: Function = () => {
  53.   }) {
  54.    
  55.     if (this.rdbStore) {
  56.       this.rdbStore.query(predicates, this.columns, (err, resultSet) => {
  57.        ..
  58.       });
  59.     }
  60.   }
  61. }
  62. 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.
复制代码


  • 其次创建灵感速记条记的RDB数据表,赋予数据的增编削查能力。
  1. import { relationalStore } from '@kit.ArkData';
  2. import Rdb from './RDB';
  3. export  class InspirationTable {
  4.   private accountTable = new Rdb(CommonConstants.INSPIRATION_TABLE.tableName, CommonConstants.INSPIRATION_TABLE.sqlCreate,
  5.     CommonConstants.INSPIRATION_TABLE.columns);
  6.   constructor(callback: Function = () => {
  7.   }) {
  8.     this.accountTable.getRdbStore(callback);
  9.   }
  10.   getRdbStore(callback: Function = () => {
  11.   }) {
  12.     this.accountTable.getRdbStore(callback);
  13.   }
  14.   insertData(inspiration: InspirationData, callback: Function) {
  15. ...
  16.     this.accountTable.insertData(valueBucket, callback);
  17.   }
  18.   deleteData(inspiration: InspirationData, callback: Function) {
  19. ...
  20.     this.accountTable.deleteData(predicates, callback);
  21.   }
  22.   updateData(inspiration: InspirationData, callback: Function) {
  23. ...
  24.     this.accountTable.updateData(predicates, valueBucket, callback);
  25.   }
  26. InspirationTable()
  27. export default  new InspirationTable() ;
  28. function generateBucket(inspiration: InspirationData): relationalStore.ValuesBucket {
  29.   let obj: relationalStore.ValuesBucket = {};
  30.   obj.inspirationName = inspiration.inspirationName;
  31.   obj.updateTime = inspiration.updateTime;
  32. ...
  33.   return obj;
  34. }
  35. 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.
复制代码
6 条记功能开发

展示的每条条记都是一个List元素,默认是一条高度固定的消息条。在用户单击后Item后,通过条件渲染,启用如下编辑选项:选择类别、可编辑内容、复制与华为分享、插入图片。


  • 选择类别
    每种条记类别都有专属的图标和颜色,根据用户的选择实时渲染整条List Item,如下所示为用户选择默认紫色灵感类别时,暂时渲染的内容做相应的渲染,当用户选择√后,再做恒久化保存。
  1.         // idea type button
  2.         if (this.isExpanded) {
  3.           Row({ space: 10 }) {
  4.             Button({ type: ButtonType.Circle, stateEffect: true }) {
  5.               Image($r(CommonConstants.CREATE_IMG))
  6.                 .fancyImage(20)
  7.             }.fancyButton(CommonConstants.CREATE_COLOR)
  8.             .onClick(() => {
  9.               this.InspiItem.inspirationColor = CommonConstants.CREATE_COLOR
  10.               this.InspiItem.inspirationType = InspirationType.CREATE_IDEA
  11.               this.InspiItem.inspirationIcon = CommonConstants.CREATE_IMG
  12.             })
  13.                 ...
  14.           }.justifyContent(FlexAlign.Center).width(this.edite_width)
  15.           .position({ x: 0, y: -15 })
  16.         }
  17. 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.
复制代码
如果用户选择了强提示类别,会触发关照时间设置,到点自动发送关照和震动响铃。

  1.                     if (this.InspiItem.inspirationType === InspirationType.ATTENTION_IDEA) {
  2.                       DatePickerDialog.show({
  3.                         start: this.startDate,
  4.                         end: new Date("2100-12-31"),
  5.                         selected: this.selectedDate,
  6.                         showTime: true,
  7.                         useMilitaryTime: true,
  8.                         disappearTextStyle: {
  9.                           color: CommonConstants.ATTENTION_COLOR,
  10.                           font: { size: '14fp', weight: FontWeight.Bold }
  11.                         },
  12.                         textStyle: {
  13.                           color: CommonConstants.ATTENTION_COLOR,
  14.                           font: { size: '18fp', weight: FontWeight.Normal }
  15.                         },
  16.                         selectedTextStyle: { color: '#ff182431', font: { size: '22fp', weight: FontWeight.Regular } },
  17.                         onDateAccept: (value: Date) => {
  18.                           // 通过Date的setFullYear方法设置按下确定按钮时的日期,这样当弹窗再次弹出时显示选中的是上一次确定的日期
  19.                           this.selectedDate = value
  20.                           BackgroundReminder.publishReminder(this.InspiItem, value);
  21.                           if (this.updateItem !== undefined) {
  22.                             console.info('inspitest-点击修改内容')
  23.                             this.updateItem(this.isInsert, this.InspiItem)
  24.                             this.isInsert = false
  25.                           }
  26.                           // this.isExpanded = false;
  27.                           this.animationClick(false);
  28.                         }
  29.                     }
  30. 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.
复制代码
如果用户选择了日程类别,会触发日程时间选择,自动关联到体系日历。

  1. else if (this.InspiItem.inspirationType === InspirationType.TODO_IDEA) {
  2.                       CalendarPickerDialog.show({
  3.                         selected: this.selectedDate,
  4.                         onAccept: (value) => {
  5.                           CalenderMessage.publishCalenderEvent(this.InspiItem, value);
  6.                           if (this.updateItem !== undefined) {
  7.                             console.info('inspitest-点击修改内容')
  8.                             this.updateItem(this.isInsert, this.InspiItem)
  9.                             this.isInsert = false
  10.                           }
  11.                           // this.isExpanded = false;
  12.                           this.animationClick(false);
  13.                           console.info("calendar onAccept:" + JSON.stringify(value))
  14.                         }
  15.                       })
  16.                     }
  17. 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.
复制代码


  • 可编辑内容
    条记内容包罗最近编辑时间(Text)、可编辑条记文本(InpuText)、选择的图片(Image)。这部分功能利用根本组件即可实现。
  • 复制、华为分享

    • 利用pasteboard接口实现复制。

  1. // copy
  2.               Column() {
  3.                   Image($r('app.media.ic_public_copy')).fancyImage(25)
  4.                 }
  5.                 .width('20%')
  6.                 .onClick(() => {
  7.                   if (this.TempInspiName === '') {
  8.                     promptAction.showToast({
  9.                       message: '内容为空',
  10.                       duration: 1500
  11.                     })
  12.                     return;
  13.                   }
  14.                   let text: string = this.TempInspiName;
  15.                   let pasteData: pasteboard.PasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text);
  16.                   let systemPasteBoard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard();
  17.                   systemPasteBoard.setData(pasteData).catch((err: BusinessError) => {
  18.                     console.error(`Failed to set pastedata. Code: ${err.code}, message: ${err.message}`);
  19.                   });
  20.                   let subText = this.TempInspiName.substring(0, 4);
  21.                   if (subText.length < this.TempInspiName.length) { //只提示部分内容
  22.                     subText = subText + '...'
  23.                   }
  24.                 })
  25. 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.
复制代码


  • 利用systemShare接口即可实现华为分享。
  1.                 // share
  2.                 Column() {
  3.                   Image($r('app.media.ic_public_share')).fancyImage(25)
  4.                 }.width('20%')
  5.                 .onClick(() => {
  6.                   let ShareDta: systemShare.SharedData = new systemShare.SharedData({
  7.                     utd: utd.UniformDataType.PLAIN_TEXT,
  8.                     content: this.TempInspiName
  9.                   });
  10.                   // 构建ShareController
  11.                   let ShareController: systemShare.ShareController = new systemShare.ShareController(ShareDta);
  12.                   // 获取UIAbility上下文对象
  13.                   let ShareContext: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
  14.                   // 注册分享面板关闭监听
  15.                   ShareController.on('dismiss', () => {
  16.                     console.log('Share panel closed');
  17.                     // 分享结束,可处理其他业务。
  18.                   });
  19.                   // 进行分享面板显示
  20.                   ShareController.show(ShareContext, {
  21.                     previewMode: systemShare.SharePreviewMode.DETAIL,
  22.                     selectionMode: systemShare.SelectionMode.SINGLE
  23.                   });
  24.                 })
  25. 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.
复制代码


  • 插入图片
    通过picker.PhotoViewPicker访问用户相机和相册,保护用户隐私,利用也快捷方便。

  1. //add camera or photoPicker
  2.                 Column() {
  3.                   Image($r('app.media.ic_public_camera'))
  4.                     .fancyImage(25)
  5.                 }
  6.                 .width('16%')
  7.                 .onClick(() => {
  8.                   if (this.TempInspiPicIndex < 5) {
  9.                     const photoSelectOptions = new picker.PhotoSelectOptions();
  10.                     photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
  11.                     photoSelectOptions.maxSelectNumber = 5 - this.TempInspiPicIndex;
  12.                     const photoViewPicker = new picker.PhotoViewPicker();
  13.                     //调用select()接口拉起图库界面进行文件选择,文件选择成功后,返回PhotoSelectResult结果集
  14.                     photoViewPicker.select(photoSelectOptions)
  15.                       .then(async (photoSelectResult: picker.PhotoSelectResult) => {
  16.                         //用一个全局变量存储返回的uri
  17.                         this.selectedImage = photoSelectResult.photoUris
  18.                         for (let i = 0; i < photoSelectResult.photoUris.length; i += 1) {
  19.                           this.TempInspiPic += photoSelectResult.photoUris[i] + '|';
  20.                           this.TempInspiPicIndex += 1;
  21.                         }                       
  22.                         console.info('photoViewPicker.select to file succeed and uris are:' + this.TempInspiPic);            
  23.                       })
  24.                       .catch((err: BusinessError) => {
  25.                         console.error(`Invoke photoViewPicker.select failed, code is ${err.code}, message is ${err.message}`);
  26.                       })
  27.                   } else {
  28.                     promptAction.showToast({
  29.                       message: '图片超出限制',
  30.                       duration: 1500
  31.                     })
  32.                   }
  33.                 })
  34. 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.
复制代码
通过开发上述编辑选项功能,实现的内容编辑效果如下图所示:

7 动效开发

APP的开发离不开动画,HarmonyOS NEXT ArkUI中提供多种动画接口(属性动画、转场动画等),灵感速记中利用了转场动画、弹簧效果等动效,给用户舒服的视觉体验。
通过根本的组件转场接口transition与TransitionEffect的组合利用,界说出一镜到底的操纵效果。如条记内容在睁开或收起时,到场下动画修饰:
  1.           .transition(TransitionEffect.asymmetric(
  2.             TransitionEffect.opacity(0)
  3.               .animation({ curve: curves.cubicBezierCurve(0.33, 0, 0.67, 1), duration: 200, delay: 150 }),
  4.             TransitionEffect.opacity(0)
  5.               .animation({ curve: curves.cubicBezierCurve(0.33, 0, 0.67, 1), duration: 200 }),
  6.           ))
  7. 1.2.3.4.5.6.
复制代码
条记睁开、收起动画效果立竿见影:

8 共享消息与灵动看板

灵感速记的共享消息功能,是将APP记录的内容分享到生态硬件(灵动看板),在灵动开板上点击完成,APP也有相应的记录。共享消息功能将条记“用起来”,发掘更多应用场景。共享消息功能主要利用了IoT技术实现,技术思绪如下图:

在APP内置了本地html网页,用于实现设置mqtt参数以及收发数据,该过程涉及应用侧与前端页面的交互,HarmonyOS NEXT的[ArkWeb(方舟Web)]提供了能力运行前端JavaScript函数、数据双向传输等能力。
这里讲解如何实现html与ArkTS之间数据交互。
起首,在启动app时,要在Index.ets的aboutToAppear()中创建一个和H5页面通信的消息通道,实现如下:
  1.   TryWebPort(): void {
  2.     try {
  3.       // 1、创建两个消息端口。
  4.       this.ports = this.webviewController.createWebMessagePorts();
  5.       // 2、在应用侧的消息端口(如端口1)上注册回调事件。
  6.       this.ports[1].onMessageEvent((result: web_webview.WebMessage) => {
  7.         let msg = 'Got msg from HTML:';
  8. ...
  9.       })
  10.       // 3、将另一个消息端口(如端口0)发送到HTML侧,由HTML侧保存并使用。
  11.       this.webviewController.postMessage('__init_port__', [this.ports[0]], '*');
  12.     } catch (error) {
  13.       promptAction.showToast({duration:2000,message:'发送失败'})
  14.       let e: business_error.BusinessError = error as business_error.BusinessError;
  15.       console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
  16.     }
  17.   }
  18. 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.
复制代码
其次,需要在本地src/main/resources/rawfile/index.html 中创建一个用于接收的监听端口,具体实现如下:
  1. // 页面
  2. var h5Port;
  3. var output = document.querySelector('.output');
  4. window.addEventListener('message', function (event) {
  5.     if (event.data === '__init_port__') {
  6.         if (event.ports[0] !== null) {
  7.             h5Port = event.ports[0]; // 1. 保存从ets侧发送过来的端口
  8.             h5Port.onmessage = function (event) {
  9.               // 2. 接收ets侧发送过来的消息.
  10.               var msg = 'Got message from ets:';
  11.               var result = event.data;
  12.               if (typeof(result) === 'string') {
  13.                 console.info(`received string message from html5, string is: ${result}`);
  14.                 msg = result;
  15.               } else if (typeof(result) === 'object') {
  16.                 if (result instanceof ArrayBuffer) {
  17.                   console.info(`received arraybuffer from html5, length is: ${result.byteLength}`);
  18.                   msg = msg + 'lenght is ' + result.byteLength;
  19.                 } else {
  20.                   console.info('not support');
  21.                 }
  22.               } else {
  23.                 console.info('not support');
  24.               }
  25.               // this.PositionName  = msg.toString();
  26.       
  27.             }
  28.         }
  29.     }
  30. })
  31. 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.
复制代码
本地的H5可以通过与ets建立的消息通道,直接发送数据到用户页面,这个通道也可以用来接收H5发送回来的数据.
  1. // 使用h5Port往ets侧发送消息.
  2. function PostMsgToEts(data) {
  3.     console.info('H5 to Ets data:'+data);
  4.     if (h5Port) {
  5.       h5Port.postMessage(data);
  6.     } else {
  7.       console.error('h5Port is null, Please initialize first');
  8.     }
  9. }
  10. // 调用接口发送数据到ets用户页面,便于存储和展示
  11. this.PostMsgToEts(jsonObjTaskNumber.toString()+jsonObjTaskChecked.toString());
  12. 1.2.3.4.5.6.7.8.9.10.11.
复制代码


在最后

如果你觉得这篇内容对你还蛮有资助,我想邀请你帮我三个小忙:
点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
关注小编,同时可以等待后续文章ing

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

篮之新喜

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表