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#创建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>