HarmonyOS 鸿蒙Next 使用5.0sdk调用屏幕录制获取不到权限
HarmonyOS 鸿蒙Next 使用5.0sdk调用屏幕录制获取不到权限
1、没加屏幕权限(之前在entry/src/main/module.json5中声明ohos.permission.CAPTURE_SCREEN会安装失败,若使用requestPermissionsFromUser会获取不到),使用5.0sdk,
1、根据https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/using-avscreencapture-for-file-V5 然后调用OH_AVScreenCapture_Init,返回AV_SCREEN_CAPTURE_ERR_OPERATE_NOT_PERMIT。
1)希望提供屏幕录制方法
2)目前使用的屏幕录制SDK不好处理callback回调(无法设置userData)(可不解决)
截屏权限(ohos.permission.CAPTURE_SCREEN)仅系统应用可申请,当前并不支持三方应用申请该权限。 可以使用以下权限:
'ohos.permission.MICROPHONE',
'ohos.permission.READ_MEDIA',
'ohos.permission.WRITE_MEDIA'
不需要ohos.permission.CAPTURE_SCREEN权限。
有个demo参考下:
EntryAbility.ets:
import {
abilityAccessCtrl,
AbilityConstant,
common,
Permissions,
UIAbility,
Want,
WantAgent,
wantAgent
} from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
const permissions: Array<Permissions> =
['ohos.permission.MICROPHONE', 'ohos.permission.READ_MEDIA', 'ohos.permission.WRITE_MEDIA',
'ohos.permission.SYSTEM_FLOAT_WINDOW'];
// 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext
function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
// requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
atManager.requestPermissionsFromUser(context, permissions).then((data) => {
let grantStatus: Array<number> = data.authResults;
let length: number = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] === 0) {
// 用户授权,可以继续访问目标操作
} else {
// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
return;
}
}
// 授权成功
}).catch((err: BusinessError) => {
console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
})
}
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy(): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
reqPermissionsFromUser(permissions, this.context);
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
});
}
onWindowStageDestroy(): void {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground(): void {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground(): void {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
let wantAgentInfo: wantAgent.WantAgentInfo = {
// 点击通知后,将要执行的动作列表
wants: [
{
bundleName: "com.example.myapplication",
abilityName: "EntryAbility"
}
],
// 点击通知后,动作类型
actionType: wantAgent.OperationType.START_ABILITY,
// 使用者自定义的一个私有值
requestCode: 0,
// 点击通知后,动作执行属性
wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
try {
// 通过wantAgent模块下getWantAgent方法获取WantAgent对象
wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
try {
backgroundTaskManager.startBackgroundRunning(this.context,
backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
console.info("Operation startBackgroundRunning succeeded");
}).catch((error: BusinessError) => {
console.error(`Operation startBackgroundRunning failed. code is ${error.code} message is ${error.message}`);
});
} catch (error) {
console.error(`Operation startBackgroundRunning failed. code is ${(error as BusinessError).code} message is ${(error as BusinessError).message}`);
}
});
} catch (error) {
console.error(`Operation getWantAgent failed. code is ${(error as BusinessError).code} message is ${(error as BusinessError).message}`);
}
}
};
Index.ets:
import { hilog } from '@kit.PerformanceAnalysisKit';
import testNapi from 'libentry.so';
import { fileIo, fileUri } from '@kit.CoreFileKit';
@Entry
@Component
struct Index {
@State message: string = 'Screen Capture';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
hilog.info(0x0000, 'testTag', 'Test NAPI 2 + 3 = %{public}d', testNapi.add(2, 3));
})
Button('start capture')
.onClick(() => {
let path = getContext(this).cacheDir + '/test.mp4';
let file:fileIo.File = fileIo.openSync(path,fileIo.OpenMode.READ_WRITE| fileIo.OpenMode.CREATE);
hilog.info(0x0000, 'testTag', 'Test NAPI 2 + 3 = %{public}d', testNapi.screencapture(file.fd));
})
Button('stop capture')
.onClick(() => {
hilog.info(0x0000, 'testTag', 'Test NAPI 2 + 3 = %{public}d', testNapi.stopcapture());
})
Button('open mic')
.onClick(() => {
hilog.info(0x0000, 'testTag', 'Test NAPI 2 + 3 = %{public}d', testNapi.openMic());
})
Button('close mic')
.onClick(() => {
hilog.info(0x0000, 'testTag', 'Test NAPI 2 + 3 = %{public}d', testNapi.closeMic());
})
}
.width('100%')
}
.height('100%')
}
}
napi_init.cpp:
#include "napi/native_api.h"
#include <multimedia/player_framework/native_avscreen_capture.h>
#include <multimedia/player_framework/native_avscreen_capture_base.h>
#include <multimedia/player_framework/native_avscreen_capture_errors.h>
#include <fcntl.h>
#include "string"
#include "unistd.h"
#include <hilog/log.h>
void OnError(OH_AVScreenCapture *capture, int32_t errorCode, void *userData) {
OH_LOG_Print(LOG_APP, LOG_INFO, 1, "test", "error:%{public}d", errorCode);
(void)capture;
(void)errorCode;
(void)userData;
}
// void OnStateChange(struct OH_AVScreenCapture *capture, OH_AVScreenCaptureStateCode stateCode, void *userData) {
// (void)capture;
//
// OH_LOG_Print(LOG_APP, LOG_INFO, 1, "test", "stateCode:%{public}d", stateCode);
// if (stateCode == OH_SCREEN_CAPTURE_STATE_STARTED) {
// // 处理状态变更
// // 可选 配置录屏旋转
// int32_t retRotation = OH_AVScreenCapture_SetCanvasRotation(capture, true);
// }
//
// if (stateCode == OH_SCREEN_CAPTURE_STATE_INTERRUPTED_BY_OTHER) {
// // 处理状态变更
// }
// (void)userData;
// }
void OnStateChange(struct OH_AVScreenCapture *capture, OH_AVScreenCaptureStateCode stateCode, void *userData) {
if (stateCode == OH_SCREEN_CAPTURE_STATE_STARTED) {
OH_LOG_INFO(LOG_APP, "==DEMO== ScreenCapture OnStateChange started");
// 处理状态变更
// 可选 配置录屏旋转
}
if (stateCode == OH_SCREEN_CAPTURE_STATE_INTERRUPTED_BY_OTHER) {
// 处理状态变更
}
(void)userData;
}
static napi_value Add(napi_env env, napi_callback_info info) {
size_t requireArgc = 2;
size_t argc = 2;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
napi_valuetype valuetype0;
napi_typeof(env, args[0], &valuetype0);
napi_valuetype valuetype1;
napi_typeof(env, args[1], &valuetype1);
double value0;
napi_get_value_double(env, args[0], &value0);
double value1;
napi_get_value_double(env, args[1], &value1);
napi_value sum;
napi_create_double(env, value0 + value1, &sum);
return sum;
}
static struct OH_AVScreenCapture *capture = {};
static napi_value Screencapture(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
int32_t value0;
napi_get_value_int32(env, args[0], &value0);
OH_AVScreenCaptureConfig config;
OH_AudioCaptureInfo innerCapInfo = {.audioSampleRate = 48000, .audioChannels = 2, .audioSource = OH_ALL_PLAYBACK};
OH_AudioCaptureInfo micCapInfo = {.audioSampleRate = 48000, .audioChannels = 2, .audioSource = OH_MIC};
OH_AudioEncInfo audioEncInfo = {.audioBitrate = 48000, .audioCodecformat = OH_AudioCodecFormat::OH_AAC_LC};
OH_VideoCaptureInfo videoCapInfo = {
.videoFrameWidth = 720, .videoFrameHeight = 1080, .videoSource = OH_VIDEO_SOURCE_SURFACE_RGBA};
OH_VideoEncInfo videoEncInfo = {
.videoCodec = OH_VideoCodecFormat::OH_H264, .videoBitrate = 2000000, .videoFrameRate = 30};
OH_AudioInfo audioInfo = {.micCapInfo = micCapInfo, .innerCapInfo = innerCapInfo, .audioEncInfo = audioEncInfo};
OH_VideoInfo videoInfo = {.videoCapInfo = videoCapInfo, .videoEncInfo = videoEncInfo};
config = {
.captureMode = OH_CAPTURE_HOME_SCREEN,
.dataType = OH_CAPTURE_FILE,
.audioInfo = audioInfo,
.videoInfo = videoInfo,
};
capture = OH_AVScreenCapture_Create();
// 初始化录屏参数,传入配置信息OH_AVScreenRecorderConfig
OH_RecorderInfo recorderInfo;
// std::string SCREEN_CAPTURE_ROOT = "/data/storage/el2/base/files/";
// int32_t outputFd = open((SCREEN_CAPTURE_ROOT + "screen01.mp4").c_str(), O_RDWR | O_CREAT, 0777);
std::string fileUrl = "fd://" + std::to_string(value0);
recorderInfo.url = const_cast<char *>(fileUrl.c_str());
recorderInfo.fileFormat = OH_ContainerFormatType::CFT_MPEG_4;
config.recorderInfo = recorderInfo;
config.captureMode = OH_CAPTURE_HOME_SCREEN;
config.dataType = OH_CAPTURE_FILE;
// 设置回调
//OH_AVScreenCapture_SetErrorCallback(capture, OnError, nullptr);
OH_AVScreenCapture_SetStateCallback(capture, OnStateChange, nullptr);
//OH_AVScreenCapture_SetDataCallback(capture, OnBufferAvailable, nullptr);
//OH_AVScreenCapture_SetCanvasRotation(capture, true);
// 进行初始化操作
int32_t retInit = OH_AVScreenCapture_Init(capture, config);
OH_LOG_Print(LOG_APP, LOG_INFO, 1, "test", "init:%{public}d", retInit);
// 开始录屏
//OH_AVScreenCapture_SetMicrophoneEnabled(capture, false);
int32_t micRet = OH_AVScreenCapture_SetMicrophoneEnabled(capture, true);
int32_t retStart = OH_AVScreenCapture_StartScreenRecording(capture);
OH_LOG_Print(LOG_APP, LOG_INFO, 1, "test", "start:%{public}d", retStart);
// 录制10s
//sleep(10);
// 结束录屏
//int32_t retStop = OH_AVScreenCapture_StopScreenRecording(capture);
// 释放ScreenCapture
//int32_t retRelease = OH_AVScreenCapture_Release(capture);
// 返回调用结果,示例仅返回随意值
napi_value sum;
napi_create_double(env, 7, &sum);
return sum;
}
static napi_value Stopcapture(napi_env env, napi_callback_info info) {
// 结束录屏
int32_t retStop = OH_AVScreenCapture_StopScreenRecording(capture);
OH_LOG_Print(LOG_APP, LOG_INFO, 1, "test", "STOP:%{public}d", retStop);
// 释放ScreenCapture
int32_t retRelease = OH_AVScreenCapture_Release(capture);
napi_value res;
napi_create_int32(env, retRelease, &res);
return res;
}
static napi_value OpenMic(napi_env env, napi_callback_info info) {
int32_t micRet = OH_AVScreenCapture_SetMicrophoneEnabled(capture, true);
OH_LOG_Print(LOG_APP, LOG_INFO, 1, "test", "open mic:%{public}d", micRet);
napi_value sum;
napi_create_double(env, 1, &sum);
return sum;
}
static napi_value CloseMic(napi_env env, napi_callback_info info) {
int32_t micRet = OH_AVScreenCapture_SetMicrophoneEnabled(capture, false);
OH_LOG_Print(LOG_APP, LOG_INFO, 1, "test", "close mic:%{public}d", micRet);
napi_value sum;
napi_create_double(env, 1, &sum);
return sum;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor desc[] = {
{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
{"screencapture", nullptr, Screencapture, nullptr, nullptr, nullptr, napi_default, nullptr},
{"stopcapture", nullptr, Stopcapture, nullptr, nullptr, nullptr, napi_default, nullptr},
{"openMic", nullptr, OpenMic, nullptr, nullptr, nullptr, napi_default, nullptr},
{"closeMic", nullptr, CloseMic, nullptr, nullptr, nullptr, napi_default, nullptr},
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_END
static napi_module demoModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "entry",
.nm_priv = ((void *)0),
.reserved = {0},
};
extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
现在只有RGBA模式,YUV没有适配,具体实现可参考此demo:
录屏存文件
录屏取码流
弹窗申请权限
更多关于HarmonyOS 鸿蒙Next 使用5.0sdk调用屏幕录制获取不到权限的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
针对HarmonyOS 鸿蒙Next使用5.0 SDK调用屏幕录制获取不到权限的问题,以下是一些可能的解决方案:
- 检查权限配置:确保在
module.json5
文件中已经正确配置了屏幕录制所需的权限。这通常是基础的权限配置步骤,不可或缺。 - 动态申请权限:在运行时动态申请屏幕录制权限,并处理用户的授权结果。若用户拒绝授权,应给予适当的提示,并引导用户前往系统设置开启权限。
- 确认SDK版本:确保你使用的HarmonyOS SDK版本支持屏幕录制功能。不同版本的SDK可能有所不同,功能支持和权限要求也可能存在差异。
- 检查代码实现:仔细检查调用屏幕录制功能的代码实现,确保没有逻辑错误或遗漏。
如果上述方法仍然无法解决问题,可能是由于系统或其他未知因素导致的。此时,建议直接联系官网客服,以便获得更专业的帮助。官网地址是:https://www.itying.com/category-93-b0.html。