【每日学点鸿蒙知识】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>
相关推荐
笑中取栗14 小时前
华为HCSA-传输接入H19-473题库
网络·华为·题库·hcsa
Python私教14 小时前
鸿蒙 NEXT 也能接 MCP?用 ArkTS 跑通 AI Agent 工具链
人工智能·华为·harmonyos
Mr数据杨15 小时前
【CanMV K210】显示交互 OLED 128x64 智能状态面板设计
人工智能·交互·硬件开发·canmv k210
极客范儿16 小时前
华为HCIP网络工程师认证—OSPF
网络·华为·智能路由器
Swift社区16 小时前
分布式能力在鸿蒙 PC 上到底怎么用?
分布式·华为·harmonyos
曾响铃16 小时前
制造跃升:传统产业正迈入数智化转型的价值兑现期
华为
nashane1 天前
HarmonyOS 6学习:外接键盘CapsLock与长截图功能的实战调试与完整解决方案
学习·华为·计算机外设·harmonyos
aqi001 天前
一文理清 HarmonyOS 6.0.2 涵盖的十个升级点
android·华为·harmonyos·鸿蒙·harmony
环信即时通讯云1 天前
环信Flutter UIKit适配鸿蒙实战指南
flutter·华为·harmonyos