当前位置: 首页 > article >正文

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

1、HarmonyOS navigation跳转不存在的url,不会抛异常,会跳转到空白页面?

使用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#%E5%88%9B%E5%BB%BAmenu%E7%BB%84%E4%BB%B6

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>

http://www.kler.cn/a/457481.html

相关文章:

  • 基于单片机的家庭智能垃圾桶(论文+源码)
  • 【记录】Angr|Angr 标准库函数替换怎么看哪些库函数被Angr支持?
  • kafka开机自启失败问题处理
  • Alist-Sync-Web 网盘自动同步,网盘备份相互备份
  • 38 Opencv HOG特征检测
  • websocket-sharp:.NET平台上的WebSocket客户端与服务器开源库
  • 2024/12/29 黄冈师范学院计算机学院网络工程《路由期末复习作业一》
  • Linux day 1129
  • java高频面试之SE-05
  • 关于ESD(静电放电)等级的划分
  • .net8使用log4.net并自定义日志表的字段
  • Django管理界面自定义操作重启ECS服务
  • 业务智能化的关键:探索事件驱动的业务规则模型
  • 网络的类型
  • 面试场景题系列:设计键值存储系统
  • 在Bash Shell脚本中创建和使用变量
  • 如何正确使用Jmeter
  • vue2使用pdfjs-dist和jsPDF生成pdf文件
  • 多显卡服务器如何设置使用集成显卡输出信号?
  • 从零开始开发纯血鸿蒙应用之UI封装
  • HarmonyOS NEXT应用开发实战:一分钟写一个网络接口,JsonFormat插件推荐
  • java开发配置文件集合
  • E6 中的 扩展运算符(Spread) 和 剩余运算符(Rest)
  • 游戏陪玩系统:国际版JAVA游戏陪玩系统源码陪练APP源码H5源码电竞系统源码支持Android+IOS+H5
  • 最新常见的图数据库对比,选型,架构,性能对比
  • 大数据技术-Hadoop(二)HDFS的介绍与使用