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)(可不解决)

2 回复

截屏权限(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:

录屏存文件

https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/media/media/using-avscreencapture-for-file.md

录屏取码流

https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/media/media/using-avscreencapture-for-buffer.md

弹窗申请权限

https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/AccessToken/request-user-authorization.md

更多关于HarmonyOS 鸿蒙Next 使用5.0sdk调用屏幕录制获取不到权限的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


针对HarmonyOS 鸿蒙Next使用5.0 SDK调用屏幕录制获取不到权限的问题,以下是一些可能的解决方案:

  1. 检查权限配置:确保在module.json5文件中已经正确配置了屏幕录制所需的权限。这通常是基础的权限配置步骤,不可或缺。
  2. 动态申请权限:在运行时动态申请屏幕录制权限,并处理用户的授权结果。若用户拒绝授权,应给予适当的提示,并引导用户前往系统设置开启权限。
  3. 确认SDK版本:确保你使用的HarmonyOS SDK版本支持屏幕录制功能。不同版本的SDK可能有所不同,功能支持和权限要求也可能存在差异。
  4. 检查代码实现:仔细检查调用屏幕录制功能的代码实现,确保没有逻辑错误或遗漏。

如果上述方法仍然无法解决问题,可能是由于系统或其他未知因素导致的。此时,建议直接联系官网客服,以便获得更专业的帮助。官网地址是:https://www.itying.com/category-93-b0.html

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!