【每日学点鸿蒙知识】navigation跳转异常、默认加载移动端版本网页、Menu位置、View生成图片保存相册、H5原生交互

使用pushDestinationByName可以捕获到异常,参考如下:

this.pageStack.pushDestinationByName('PageOne', "PageOne Param")
  .catch((error: BusinessError) => {
    console.error(`Push destination failed, error code = ${error.code}, error.message = ${error.message}.`);
  }).then(() => {
  console.error('Push destination succeed.');
});
2、HarmonyOS webview默认加载的页面如何设置默认加载移动端版本的页面?
import webview from '@ohos.web.webview';

@Entry
@Component
struct Page2 {
  webController: webview.WebviewController = new webview.WebviewController();
  aboutToAppear(): void {
    webview.WebviewController.setWebDebuggingAccess(true)
  }
  build() {
    Row() {
      Column() {
        Web({src: "https://www.huawei.com;, controller:this.webController}).domStorageAccess(true)
          .onControllerAttached(() => {
          let newAgent = "Mozilla/5.0 (Phone; OpenHarmony 4.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 ArkWeb/4.1.6.1 Mobile";
          this.webController.setCustomUserAgent(newAgent)
        })
      }
      .width('100%')
    }
    .height('100%')
  }
}
3、HarmonyOS 弹出的Menu位置?

点击按钮弹出menu,menu的位置无法控制,有时候在点击插件的下面,有时候在左右,是否控制menu的弹出位置

想要固定菜单位置显示,可以配置placement属性,例如Placement.BottomLeft,菜单会显示在绑定组件的下方,左边缘与绑定组件的左边缘对齐。参考文档链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ui-js-components-menu-V5#创建menu组件

4、HarmonyOS view生成图片,然后保存到相册?

view生成图片,然后保存到相册

思路如下:

//1.海报布局
Column() {
  // 顶部图片
  this.renderImage(this.isHiresSong)

  // hire音质
  if (this.labelInfoJson !== null || this.labelInfoJson !== undefined) {
    this.renderHiresLabel()
  }

  // 歌词
  if (this.selectLyricList.length > 0) {
    this.renderLyric()
  }

  // 标题、作者
  this.renderTitleInfo(this.selectLyricList.length > 0)

  // 水印、二维码
  this.renderWatermarkQrc()
}
.id('placard_layout')
.backgroundColor(this.bgColor)
.margin({ top: '25vp', bottom: '48vp', left: '30vp', right: '30vp' })
.padding({ top: '16vp', bottom: '16vp', left: '16vp', right: '16vp' })
//2.存储前先判断权限(如果是应用内存储不需要权限)
注意:ohos.permission.WRITE_IMAGEVIDEO是系统权限system_basic,如果是普通应用需要通过ACL提权,
let content: Context = getContext(this)
let permissions: Array<Permissions> = ['ohos.permission.WRITE_IMAGEVIDEO']
let atManager = abilityAccessCtrl.createAtManager();
let promise = atManager.requestPermissionsFromUser(content, permissions);
let rejectNum = 0;
promise.then(async (data) => {
  let grant: number[] = data.authResults;
  let grantName: string[] = data.permissions;
  for (let i = 0; i < grant.length; i++) {
    if (grant[i] !== 0) {
      console.info(TAG, 'user reject permission request ' + grantName[i]);
      /* 用户拒绝权限 */
      rejectNum++;
    }
  }
  if (rejectNum > 0) {
    promptAction.showToast({ message: '拒绝权限' })
  } else {
    this.savePlacard()
  }
}).catch((err: Error) => {
  console.error(TAG, ' requestPermissionsFromUser, error = ' + err);
});
//3.存储
通过componentSnapshot.get("placard_layout")提供获取组件截图的能力,包括已加载的组件的截图和没有加载的组件的截图,返回image.PixelMap
组件截图只能够截取组件大小的区域,如果组件的绘制超出了它的区域,或子组件的绘制超出了父组件的区域,这些在组件区域外绘制的内容不会在截图中呈现。
componentSnapshot.get("placard_layout")
  .then((pixmap: image.PixelMap) => {
    this.pixmap = pixmap;
    // 选择存储方式
    ...
  })
//1)、直接存储到应用存储空间
image.createImagePacker().packing(pixmap, { format: "image/jpeg", quality: 98 })
  .then(((data: ArrayBuffer): void => {
    let dir = getContext().cacheDir
    let file = fs.openSync(`${dir}/xxx.jpg`, fs.OpenMode.WRITE_ONLY | fs.OpenMode.CREATE | fs.OpenMode.TRUNC)
    let len: number = fs.writeSync(file.fd, data, { encoding: "utf-8" })
    console.log(`${len}`)
  }))
//2)、ohos.file.picker拉起系统文件管理器,用户选择文件保存路径,返回uri
const photoSaveOptions = new picker.PhotoSaveOptions(); // 创建文件管理器
photoSaveOptions.newFileNames = [fileName + '.png'];
const photoViewPicker = new picker.PhotoViewPicker();
photoViewPicker.save(photoSaveOptions)
  .then((photoSaveResult) => {
    console.log(TAG, "photoSaveUri  photoSaveResult[0]" + JSON.stringify(photoSaveResult[0]))
    this.photoSaveUri = photoSaveResult[0]
  })
  .catch((err:Error) => {
    console.log(TAG, "photoSaveUri  fail" + JSON.stringify(err))
    promptAction.showToast({message:'保存失败'})
  })
//3)、通过photoAccessHelper存储到相册
let photoType = photoAccessHelper.PhotoType.IMAGE;
let extension = 'jpg';
const context = getContext(this);
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);

phAccessHelper.createAsset(photoType, extension, {
  title: fileName
}, (err, uri) => {
  if (uri != undefined) {
    console.info(TAG + 'createAsset uri' + uri);
    this.photoSaveUri = uri
    console.info(TAG + 'createAsset successfully');
  } else {
    console.error(TAG + 'createAsset failed, message = ', err);
  }
});
//完成后图片并没有存储,还需要执行写文件操作
pixmap: image.PixelMap | undefined = undefined;
@State @Watch("onPhotoSaveUriUpdate") photoSaveUri: string = '';

// 监听uri的更新,进行用户文件读写操作
onPhotoSaveUriUpdate() {
  if (this.photoSaveUri) {
    console.error(TAG, 'photoSaveUri is: ' + JSON.stringify(this.photoSaveUri));
    // 创建图像编码ImagePacker对象
    const imagePacker = image.createImagePacker();
    // 设置编码输出流和编码参数,进行图片编码
    if (this.pixmap === undefined) {
      return
    }
    imagePacker.packing(this.pixmap, { format: "image/jpeg", quality: 100 })
      .then(data => {
        // 打开文件
        let file = fs.openSync(this.photoSaveUri, fs.OpenMode.WRITE_ONLY);
        // 编码成功,写操作
        fs.writeSync(file.fd, data);
        fs.closeSync(file);
        promptAction.showToast({
          message: '已成功保存至相册',
          duration: 1000
        })
      })
      .catch((error: Error) => {
        console.error(TAG, 'Failed to pack the image. And the error is: ' + error);
      })
  }
}
5、HarmonyOS h5和HarmonyOS怎么通信?

可以参考一下这篇文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/web-app-page-data-channel-V5

前端页面和应用侧之间可以用createWebMessagePorts()接口创建消息端口来实现两端的通信。

在下面的示例中,应用侧页面中通过createWebMessagePorts方法创建消息端口,再把其中一个端口通过postMessage()接口发送到前端页面,便可以在前端页面和应用侧之间互相发送消息。

应用侧代码。

// xxx.ets
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();
  ports: webview.WebMessagePort[] = [];
  @State sendFromEts: string = 'Send this message from ets to HTML';
  @State receivedFromHtml: string = 'Display received message send from HTML';

  build() {
    Column() {
      // 展示接收到的来自HTML的内容
      Text(this.receivedFromHtml)
      // 输入框的内容发送到HTML
      TextInput({ placeholder: 'Send this message from ets to HTML' })
        .onChange((value: string) => {
          this.sendFromEts = value;
        })

      // 该内容可以放在onPageEnd生命周期中调用。
      Button('postMessage')
        .onClick(() => {
          try {
            // 1、创建两个消息端口。
            this.ports = this.controller.createWebMessagePorts();
            // 2、在应用侧的消息端口(如端口1)上注册回调事件。
            this.ports[1].onMessageEvent((result: webview.WebMessage) => {
              let msg = 'Got msg from HTML:';
              if (typeof (result) === 'string') {
                console.info(`received string message from html5, string is: ${result}`);
                msg = msg + result;
              } else if (typeof (result) === 'object') {
                if (result instanceof ArrayBuffer) {
                  console.info(`received arraybuffer from html5, length is: ${result.byteLength}`);
                  msg = msg + 'length is ' + result.byteLength;
                } else {
                  console.info('not support');
                }
              } else {
                console.info('not support');
              }
              this.receivedFromHtml = msg;
            })
            // 3、将另一个消息端口(如端口0)发送到HTML侧,由HTML侧保存并使用。
            this.controller.postMessage('__init_port__', [this.ports[0]], '*');
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        })

      // 4、使用应用侧的端口给另一个已经发送到html的端口发送消息。
      Button('SendDataToHTML')
        .onClick(() => {
          try {
            if (this.ports && this.ports[1]) {
              this.ports[1].postMessageEvent(this.sendFromEts);
            } else {
              console.error(`ports is null, Please initialize first`);
            }
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        })
      Web({ src: $rawfile('index.html'), controller: this.controller })
    }
  }
}

前端页面代码:

<!--index.html-->
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebView Message Port Demo</title>
</head>
<body>
    <h1>WebView Message Port Demo</h1>
    <div>
        <input type="button" value="SendToEts" onclick="PostMsgToEts(msgFromJS.value);"/><br/>
        <input id="msgFromJS" type="text" value="send this message from HTML to ets"/><br/>
    </div>
    <p class="output">display received message send from ets</p>
</body>
<script>
var h5Port;
var output = document.querySelector('.output');
window.addEventListener('message', function (event) {
    if (event.data === '__init_port__') {
        if (event.ports[0] !== null) {
            h5Port = event.ports[0]; // 1. 保存从应用侧发送过来的端口。
            h5Port.onmessage = function (event) {
              // 2. 接收ets侧发送过来的消息。
              var msg = 'Got message from ets:';
              var result = event.data;
              if (typeof(result) === 'string') {
                console.info(`received string message from html5, string is: ${result}`);
                msg = msg + result;
              } else if (typeof(result) === 'object') {
                if (result instanceof ArrayBuffer) {
                  console.info(`received arraybuffer from html5, length is: ${result.byteLength}`);
                  msg = msg + 'length is ' + result.byteLength;
                } else {
                  console.info('not support');
                }
              } else {
                console.info('not support');
              }
              output.innerHTML = msg;
            }
        }
    }
})
// 3. 使用h5Port向应用侧发送消息。
function PostMsgToEts(data) {
    if (h5Port) {
      h5Port.postMessage(data);
    } else {
      console.error('h5Port is null, Please initialize first');
    }
}
</script>
</html>
相关推荐
轻口味7 小时前
【每日学点鸿蒙知识】RelativeContainer组件、List回弹、Flutter方法调用、Profiler工具等
flutter·list·harmonyos
HarmonyOS开发者8 小时前
《HarmonyOS第一课》焕新升级,赋能开发者快速掌握鸿蒙应用开发
华为·harmonyos
塞尔维亚大汉9 小时前
【OpenHarmony】 鸿蒙网络请求库之httpclient
网络协议·harmonyos
NanoNerd10 小时前
使用 4 种主要方法将数据从 HTC 传输到华为
华为·传输·步骤
niech_cn11 小时前
前端路由layout布局处理以及菜单交互(三)
前端·javascript·交互
我是全栈架构师12 小时前
HarmonyOS Next ArkUI @State @Prop @Link @Provide @Consume笔记
harmonyos·arkts
guo_zhen_qian13 小时前
鸿蒙工程签名编译和上架
华为·harmonyos
执着的小火车13 小时前
【2024华为OD-E卷-100分-火星文计算】(题目+思路+Java&C++&Python解析)
java·数据结构·c++·算法·华为od·华为
IT考试认证14 小时前
2024年变题后华为数通H12-821更新题库
网络·华为·智能路由器·h12-821
个案命题15 小时前
纯血鸿蒙ArkUI选项卡布局详解
华为·harmonyos