HarmonyOS鸿蒙Next中输入法拓展申请剪切板权限报错code: 401

HarmonyOS鸿蒙Next中输入法拓展申请剪切板权限报错code: 401

  1. 使用场景 输入法拓展 InputMethodExtensionAbility 申请剪切板权限
  2. 在AGC侧申请Profile文件,将用于后续的应用签名信息配置。(已完成配置)
  3. 在module.json5配置文件中声明权限
    1. 相关配置
      "requestPermissions": [
            {
              "name" :  "ohos.permission.READ_PASTEBOARD",
              "reason": "$string:Permission_reason_clipboard",
              "usedScene": {
                "abilities": [
                  "InputMethodExtensionAbility"
                ],
                "when": "inuse"
              }
            }
          ]
      
  4. 通过弹窗向用户申请权限。 相关代码
    /**
     * 请求权限(适用于 UIAbilityContext)
     * @param permissions 权限数组
     * @param context UIAbilityContext
     */
    export function requestPermissionsFromUser(permissions: Array<Permissions>, context: common.UIExtensionContext): 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) {
            hilog.info(DOMAIN, TAG, "[Permissions] 权限已授予: %{public}s", permissions[i]);
          } else {
            hilog.warn(DOMAIN, TAG, "[Permissions] 权限被拒绝: %{public}s", permissions[i]);
          }
        }
      }).catch((err: BusinessError) => {
        hilog.error(DOMAIN, TAG, "[Permissions] 请求权限失败: Code=%{public}d, message=%{public}s", err.code, err.message);
      });
    }
    
    /**
     * 请求剪贴板权限(从 GlobalContext 获取 context)
     * @returns Promise<boolean> 返回 true 如果权限请求成功并被授予
     */
    export async function requestClipboardPermission(): Promise<boolean> {
      const context = GlobalContext.getContext();
      
      if (!context) {
        hilog.warn(DOMAIN, TAG, "[Permissions] 无法获取 context,无法请求权限");
        return false;
      }
    
      // 尝试将 context 作为 UIAbilityContext 使用
      // 如果 context 是 InputMethodExtensionContext,requestPermissionsFromUser 会失败
      try {
        // 尝试作为 UIAbilityContext 使用
        const uiAbilityContext = context as common.UIAbilityContext;
        return new Promise<boolean>((resolve) => {
          let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
          const permissions: Array<Permissions> = [CLIPBOARD_PERMISSION];
          
          atManager.requestPermissionsFromUser(uiAbilityContext, permissions).then((data) => {
            let grantStatus: Array<number> = data.authResults;
            if (grantStatus.length > 0 && grantStatus[0] === 0) {
              hilog.info(DOMAIN, TAG, "[Permissions] 剪贴板权限已授予");
              resolve(true);
            } else {
              hilog.warn(DOMAIN, TAG, "[Permissions] 剪贴板权限被拒绝");
              resolve(false);
            }
          }).catch((err: BusinessError) => {
            hilog.error(DOMAIN, TAG, "[Permissions] 请求剪贴板权限失败: Code=%{public}d, message=%{public}s", err.code, err.message);
            resolve(false);
          });
        });
      } catch (e) {
        hilog.warn(DOMAIN, TAG, "[Permissions] 无法请求权限,context 类型不支持: %{public}s", JSON.stringify(e));
        return false;
      }
    }
    
    // 全局上下文对象
    import { common } from '[@kit](/user/kit).AbilityKit';
    import { InputMethodExtensionContext } from '[@kit](/user/kit).IMEKit';
    
    /**
     * 全局上下文对象
     * 用于保存和访问全局的 Context
     */
    export class GlobalContext {
      private static context: common.UIAbilityContext | InputMethodExtensionContext | undefined = undefined;
    
      /**
       * 初始化全局 Context
       * @param context UIAbilityContext 或 InputMethodExtensionContext
       */
      public static initContext(context: common.UIAbilityContext | InputMethodExtensionContext): void {
        GlobalContext.context = context;
      }
    
      /**
       * 获取全局 Context
       * @returns UIAbilityContext 或 InputMethodExtensionContext
       */
      public static getContext(): common.UIAbilityContext | InputMethodExtensionContext | undefined {
        return GlobalContext.context;
      }
    
    
    }
    
    
    // 全局context 注册
    export default class InputDemoService extends InputMethodExtensionAbility {
    
      onCreate(want: Want): void {
        // 初始化全局 Context
        GlobalContext.initContext(this.context);
        
        keyboardController.onCreate(this.context); // 初始化窗口并注册对输入法框架的事件监听
      }
    
      onDestroy(): void {
        keyboardController.onDestroy(); // 销毁窗口并去注册事件监听
      }
    }
    

现象: 调用 requestClipboardPermission() 报 {code: 401},

查找了一下 说有可能是上下文的问题, 不知道咋修改, 望大佬求助


更多关于HarmonyOS鸿蒙Next中输入法拓展申请剪切板权限报错code: 401的实战教程也可以访问 https://www.itying.com/category-93-b0.html

9 回复

小伙伴你好,此问题是 requestPermissionsFromUser 的 permissionList 填写错误,应填写 ohos.permission.READ_PASTEBOARD

参考示例:

const permissions: Array<Permissions> = ["ohos.permission.READ_PASTEBOARD"];
      
atManager.requestPermissionsFromUser(uiAbilityContext, permissions).then((data) => {
  let grantStatus: Array<number> = data.authResults;
  if (grantStatus.length > 0 && grantStatus[0] === 0) {
    hilog.info(DOMAIN, TAG, "[Permissions] 剪贴板权限已授予");
    resolve(true);
  } else {
    hilog.warn(DOMAIN, TAG, "[Permissions] 剪贴板权限被拒绝");
    resolve(false);
  }
}).catch((err: BusinessError) => {
  hilog.error(DOMAIN, TAG, "[Permissions] 请求剪贴板权限失败: Code=%{public}d, message=%{public}s", err.code, err.message);
  resolve(false);
});

更多关于HarmonyOS鸿蒙Next中输入法拓展申请剪切板权限报错code: 401的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


const CLIPBOARD_PERMISSION: Permissions = 'ohos.permission.READ_PASTEBOARD';

你好, 我用的是常量, 应该不是这个问题,

小伙伴你好,那就是你的 Context 类型错了

这里可以参考一下 2楼的 代码示例

401 的报错信息如下: Parameter error. Possible causes: 1.Mandatory parameters are left unspecified; 2.Incorrect parameter types.

const ctx = this.getUIContext().getHostContext() // 通过 UIContext 获取全局的 Context
const atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
const permissions: Array<Permissions> = ["ohos.permission.READ_PASTEBOARD"];
atManager.requestPermissionsFromUser(ctx, permissions);

我有个问题哈, 因为我定义了一个 GlobalContext, 为什么这个 GlobalContext 不是全局的 Context, 如果我想在某个工具类里直接能 this.getUIContext().getHostContext() 要怎么操作

小伙伴你好,你这里的 Context 是通过 InputMethodExtensionAbility 获取的,所以这里的上下文应该是这个输入框能力的上下文。而 atManager 中 requestPermissionsFromUser 方法需要的是 UIAbility 的上下文,所以小伙伴需要通过 EntryAbility 的 Context 去拉起。

鸿蒙Next中输入法扩展申请剪切板权限报错401,这是权限申请被系统拒绝的通用错误代码。该错误表明当前应用或扩展的权限申请不符合系统安全策略要求。可能原因包括:应用未在配置文件正确声明所需权限、权限申请格式不规范、或系统判定该权限申请存在安全风险。需要检查应用的权限声明配置是否符合鸿蒙Next的权限管理规范,确保权限申请流程符合系统要求。

在HarmonyOS Next中,错误码401表示权限请求失败,通常是由于上下文类型不匹配导致的。从您的代码分析,问题在于InputMethodExtensionAbility的上下文是InputMethodExtensionContext,而requestPermissionsFromUser方法需要UIAbilityContext。

解决方案:

  1. 修改权限请求方法,直接使用正确的上下文:
export async function requestClipboardPermission(context: common.UIExtensionContext): Promise<boolean> {
  try {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    const permissions: Array<Permissions> = [CLIPBOARD_PERMISSION];
    
    const result = await atManager.requestPermissionsFromUser(context, permissions);
    const grantStatus: Array<number> = result.authResults;
    
    if (grantStatus.length > 0 && grantStatus[0] === 0) {
      hilog.info(DOMAIN, TAG, "[Permissions] 剪贴板权限已授予");
      return true;
    } else {
      hilog.warn(DOMAIN, TAG, "[Permissions] 剪贴板权限被拒绝");
      return false;
    }
  } catch (err: BusinessError) {
    hilog.error(DOMAIN, TAG, "[Permissions] 请求剪贴板权限失败: Code=%{public}d, message=%{public}s", err.code, err.message);
    return false;
  }
}
  1. 在InputMethodExtensionAbility中调用时直接传递上下文:
// 在需要请求权限的地方调用
requestClipboardPermission(this.context);

关键点:InputMethodExtensionContext继承自UIExtensionContext,可以直接用于权限请求,无需强制转换为UIAbilityContext。确保在InputMethodExtensionAbility的生命周期方法中直接使用this.context进行权限请求即可解决401错误。

回到顶部