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)(可不解决)
更多关于HarmonyOS 鸿蒙Next 使用5.0sdk调用屏幕录制获取不到权限的实战教程也可以访问 https://www.itying.com/category-93-b0.html
截屏权限(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。
        
      
                  
                  
                  
