1、在启动调试或运行应用/服务时,安装HAP出现错误,提示"error: install failed due to older sdk version in the device"错误信息。
这是由于编译打包所使用的SDK版本与设备镜像版本不匹配。不匹配的场景包括:
场景一:设备上的镜像版本低于编译打包的SDK版本,请更新设备镜像版本。查询设备镜像版本命令:
hdc shell param get const.ohos.apiversion
如果镜像提供的api版本为10,且应用编译所使用的SDK版本也为10,仍出现该报错,可能是由于镜像版本较低,未兼容新版本SDK校验规则,请将镜像版本更新为最新版本。
场景二:对于需要运行在OpenHarmony设备上的应用,请确认runtimeOS已改为OpenHarmony。
2、在启动调试或运行应用/服务时,安装HAP出现错误,提示"error: install sign info inconsistent"错误信息。
这由于设备上已安装的应用与新安装的应用中签名不一致。如果在Edit Configurations中勾选了"Keep Application Data"(不卸载应用,覆盖安装),并且重新进行了签名,将导致该报错。
卸载设备上已安装的应用,或取消勾选"Keep Application Data"后,重新安装新的应用。
3、如何实现RichEditor和Component成为一个整体?
RichEditor上面有个Component,现在希望RichEditor和Component成为一个整体,能够自适应光标位置进行滚动,应该如何实现,目前用Scroller无法获取RichEditor中光标的具体坐标(光标基于RichEditor的x和y位置),无法实现滚动。
可以用Scroll将RichEditor和Component包裹,通过onAreaChange的回调,调用scroller.scrollBy的能力,以此来改变滚动组件的高度。
可以参考代码:
@Entry
@Component
struct Index {
editorController = new RichEditorController()
scroller: Scroller = new Scroller()
build() {
Column() {
Scroll(this.scroller) {
Column() {
Image($r('app.media.startIcon'))
.width('100%')
.height(200)
.margin({ bottom: 20 })
RichEditor({ controller: this.editorController })
.id('RichEditor')
.width('100%')
.backgroundColor(Color.Yellow)
.onReady(() => {
this.editorController.addImageSpan($r("app.media.startIcon"),
{
imageStyle:
{
size: ["100px", "100px"]
}
})
this.editorController.addTextSpan('男生女生向前冲',
{
style:
{
fontColor: Color.Blue,
fontSize: 30
}
})
})
.onAreaChange((_, value) => {
if (_.height !== value.height) {
this.scroller.scrollBy(0, Number(value.height) - 200)
}
})
Button('getSpans-文字').onClick((event: ClickEvent) => {
let getSpans = this.editorController.getSpans({ start: 0 })
// 必须进行强转才能获取文字信息或者图片信息
let span0 = getSpans[0] as RichEditorTextSpanResult
})
Button('getSpans-图片').onClick((event: ClickEvent) => {
let getSpans = this.editorController.getSpans({ start: 0 })
let span1 = getSpans[1] as RichEditorImageSpanResult
})
Button('RichEditor获焦').onClick(() => {
focusControl.requestFocus('RichEditor')
})
}
}
.scrollable(ScrollDirection.Vertical) // 滚动方向纵向
.scrollBar(BarState.On) // 滚动条常驻显示
.scrollBarColor(Color.Gray) // 滚动条颜色
}
}
}
4、如何实现ArkTS与C/C++的数组转换?
TS2NAPI
TS侧代码:
Button("TS2NAPI")
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
let napiArray: Int32Array = new Int32Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
console.info("TS2NAPI: JS " + napiArray)
testNapi.TS2NAPI(napiArray)
})
NAPI侧代码:
// TS array 传到NAPI层
static napi_value TS2NAPI(napi_env env, napi_callback_info info) {
// 获取TS层传来的参数
size_t argc = 1;
napi_value args;
napi_get_cb_info(env, info, &argc, &args, NULL, NULL);
napi_value input_array = args;
// 获取传入数组typedarray生成input_buffer
napi_typedarray_type type; // 数据类型
napi_value input_buffer;
size_t byte_offset; // 数据偏移
size_t i, length; // 数据字节大小
napi_get_typedarray_info(env, input_array, &type, &length, NULL, &input_buffer, &byte_offset);
// 获取数组数据
void *data;
size_t byte_length;
napi_get_arraybuffer_info(env, input_buffer, &data, &byte_length);
if (type == napi_int32_array) {
int32_t *data_bytes = (int32_t *)(data);
int32_t num = length / sizeof(int32_t);
string str = "";
for (int32_t i = 0; i < num; i++) {
int32_t tmp = *((int32_t *)(data_bytes) + i);
str += (to_string(tmp) + ' ');
}
OH_LOG_INFO(LOG_APP, "TS2NAPI: C++ %{public}s", str.c_str());
}
return NULL;
}
NAPI2TS
TS侧代码:
Button("NAPI2TS")
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
let napiArray: Int32Array = testNapi.NAPI2TS()
console.info("NAPI2TS: JS " + napiArray)
})
NAPI侧代码:
// NAPI层 array 传到TS层
static napi_value NAPI2TS(napi_env env, napi_callback_info info) {
// 数据个数
int num = 10;
// 创建output_buffer
napi_value output_buffer;
void *output_ptr = NULL;
napi_create_arraybuffer(env, num * sizeof(int32_t), &output_ptr, &output_buffer);
// output_array
napi_value output_array;
napi_create_typedarray(env, napi_int32_array, num, output_buffer, 0, &output_array);
// 给output_ptr、output_buffer赋值
int32_t *output_bytes = (int32_t *)output_ptr;
for (int32_t i = 0; i < num; i++) {
output_bytes[i] = i;
}
string str = "";
for (int32_t i = 0; i < num; i++) {
int32_t tmp = *((int32_t *)(output_ptr) + i);
str += (to_string(tmp) + ' ');
}
OH_LOG_INFO(LOG_APP, "NAPI2TS: C++ %{public}s", str.c_str());
return output_array;
}
实用场景:
ArkTS侧读取rawfile的图片,传递到NAPI侧进行处理,然后传回ArkTS进行展示:
Button("Test")
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
getContext().resourceManager.getRawFileContent('test.png').then(value => {
hilog.info(0x0000, 'getRawFileContent', '%{public}s', 'OK');
const fileData: Uint8Array = value;
// 获取图片的ArrayBuffer
let buffer = fileData.buffer;
let input = new Uint8Array(buffer)
let output = testNapi.TEST(input);
let decodingOptions: image.DecodingOptions = {
editable: true,
desiredPixelFormat: 3,
}
let imageSource = image.createImageSource(output.buffer);
imageSource.createPixelMap(decodingOptions).then(map => {
this.imageSrc = map;
})
}).catch((err: BusinessError) => {
hilog.error(0x0000, 'getRawFileContent', '%{public}s', err.message);
})
})
Image(this.imageSrc)
.height(100)
.width(100)
5、如何实现顶部渐变遮罩效果?
直播间的弹幕列表顶部需要渐变遮罩效果,如何实现呢?
使用overlay通过属性linearGradient同时使用blendMode让当前浮层与下方list混合实现渐变遮罩效果。
效果图如下:
参考代码:
@Entry
@Component
struct Index {
private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
@Builder
overlayBuilder() {
Stack()
.height("100%")
.width("100%")
.linearGradient({
direction: GradientDirection.Bottom, // 渐变方向
colors: [["#00FFFFFF", 0.0], ["#FFFFFFFF", 0.3]] // 数组末尾元素占比小于1时满足重复着色效果
})
.blendMode(BlendMode.DST_IN, BlendApplyType.OFFSCREEN)
.hitTestBehavior(HitTestMode.None)
}
build() {
Column() {
List({ space: 20, initialIndex: 0 }) {
ForEach(this.arr, (item: number) => {
ListItem() {
Text('' + item)
.width('100%')
.height(100)
.fontSize(16)
.textAlign(TextAlign.Center)
.borderRadius(10)
.backgroundColor(0xFFFFFF)
}
.onClick(() => {
console.log('is click')
})
}, (item: string) => item)
}.width('90%')
.scrollBar(BarState.Off)
.overlay(this.overlayBuilder())
.blendMode(BlendMode.SRC_OVER, BlendApplyType.OFFSCREEN)
}.width('100%').height('100%').backgroundColor(0xDCDCDC).padding({ top: 5 })
}
}