Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Hmos Form Kit Router Call Refresh

ASecurity

通过router或call事件实现ArkTS卡片内容刷新,支持前台跳转和后台运行两种模式,需要配置对应权限和UIAbility,适用于卡片交互和数据更新场景

2 stars
0 votes
0 copies
0 views
Added 9/22/2026
developmenttypescriptapiperformance

Works with

cliapi

Security Analysis

A100/100

Scanned 9/22/2026

Install to Claude Code

$npx -y skills add IsKenKenYa/skills --skill hmos-form-kit-router-call-refresh --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hmos Form Kit Router Call Refresh?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Hmos Form Kit Router Call Refresh
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/iskenkenya-hmos-form-kit-router-call-refresh/badge)](https://www.skillsdirectory.com/skills/iskenkenya-hmos-form-kit-router-call-refresh)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SUB_SKILL.md
---
name: hmos-form-kit-router-call-refresh
description: 通过router或call事件实现ArkTS卡片内容刷新,支持前台跳转和后台运行两种模式,需要配置对应权限和UIAbility,适用于卡片交互和数据更新场景
---

# 通过router或call事件刷新卡片内容技能

## 功能描述

本技能实现ArkTS卡片通过router或call事件触发UIAbility并刷新卡片内容的功能。提供两种交互模式:
- **router事件**:点击卡片拉起UIAbility至前台,用户可见应用界面,适用于需要用户交互的场景
- **call事件**:点击卡片在后台拉起UIAbility,不显示应用界面,适用于后台数据更新场景

核心能力包括:
- 使用postCardAction接口触发router或call事件
- 在UIAbility中接收事件参数并处理
- 使用formProvider.updateForm接口刷新卡片内容
- 配置必要权限和UIAbility启动模式

## 使用场景

### 触发词
- "卡片刷新" - 通过事件刷新卡片内容
- "router刷新卡片" - 使用router事件刷新卡片
- "call刷新卡片" - 使用call事件后台刷新卡片
- "卡片交互" - 卡片点击事件处理
- "postCardAction" - 触发卡片事件
- "updateForm" - 更新卡片数据

### 能做
- 实现卡片点击触发UIAbility的router事件(前台跳转)
- 实现卡片点击触发UIAbility的call事件(后台运行)
- 在UIAbility中获取卡片formId和传递的参数
- 使用formProvider.updateForm更新卡片显示内容
- 处理onCreate和onNewWant生命周期中的router事件
- 处理callee监听的call事件
- 配置ohos.permission.KEEP_BACKGROUND_RUNNING权限

### 绝不做
- 不处理静态卡片的事件(静态卡片使用FormLink组件)
- 不处理message事件(message事件触发onFormEvent回调)
- 不支持多实例UIAbility的call事件(仅支持singleton模式)
- 不直接操作卡片UI(仅通过updateForm接口刷新)
- 不在卡片页面中处理业务逻辑(业务逻辑在UIAbility中处理)

### 补充
- router事件只能在点击事件中触发
- call事件需要UIAbility具备后台运行权限
- call事件仅支持launchType为singleton的UIAbility
- 从API version 9开始支持postCardAction接口
- 从API version 20开始,卡片刷新数据总大小不超过10MB,图片不超过20张

## 调用规范和规则

### 输入约束
- 卡片formId:必须为有效的字符串格式卡片标识
- abilityName:必须为当前应用下的UIAbility名称
- action参数:只能是"router"或"call"
- params参数:JSON格式的键值对,call类型必须包含method字段
- 刷新数据:formBindingData数据结构,API version 20+总大小不超过10MB

### 执行约束
- router事件:必须由用户点击触发,不能自动调用
- call事件:需要配置ohos.permission.KEEP_BACKGROUND_RUNNING权限
- UIAbility启动模式:call事件仅支持singleton模式
- 刷新时机:在UIAbility的onCreate/onNewWant或callee回调中调用updateForm
- 最大耗时:建议在3秒内完成卡片刷新,避免用户等待

### 内容约束
- 禁止在卡片页面中直接调用updateForm
- 禁止传递敏感信息(密码、token等)通过params
- 禁止在params中传递卡片内部状态变量
- 禁止使用多实例UIAbility处理call事件
- 禁止在call事件中执行耗时超过5秒的操作

### 降级约束
- 权限不足:提示用户授予后台运行权限,改用router事件
- UIAbility不存在:记录错误日志,不执行刷新
- formId无效:捕获16501001错误码,不执行操作
- 数据过大:分批更新或减少图片数量,提示数据限制
- IPC连接失败:捕获16500050错误码,延迟重试或提示网络问题

## 调用流程和步骤

### 步骤1:准备阶段 - 配置权限和UIAbility

**前置校验**:
1. 检查module.json5配置文件是否存在
2. 检查是否配置了必要的UIAbility
3. 检查call事件是否配置了ohos.permission.KEEP_BACKGROUND_RUNNING权限
4. 检查UIAbility的launchType是否为singleton(call事件)

**权限配置**:
```json
// src/main/module.json5
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.KEEP_BACKGROUND_RUNNING"
      }
    ],
    "abilities": [
      {
        "name": "WidgetEventRouterEntryAbility",
        "launchType": "standard"
      },
      {
        "name": "WidgetCalleeEntryAbility",
        "launchType": "singleton"
      }
    ]
  }
}
```

### 步骤2:卡片页面实现 - 触发router事件

**示例代码 - Router事件**:
```typescript
// entry/src/main/ets/widgetupdaterouter/pages/WidgetUpdateRouterCard.ets
let storageUpdateRouter = new LocalStorage();
@Entry(storageUpdateRouter)
@Component
struct WidgetUpdateRouterCard {
  @LocalStorageProp('routerDetail') routerDetail: ResourceStr = $r('app.string.init');
  
  build() {
    Column() {
      Column() {
        Text(this.routerDetail)
          .fontColor('#FFFFFF')
          .opacity(0.9)
          .fontSize(14)
          .margin({ top: '8%', left: '10%', right: '10%' })
          .textOverflow({ overflow: TextOverflow.Ellipsis })
          .maxLines(2)
      }.width('100%').height('50%')
      .alignItems(HorizontalAlign.Start)
      
      Row() {
        Button() {
          Text($r('app.string.JumpLabel'))
            .fontColor('#45A6F4')
            .fontSize(12)
        }
        .width(120)
        .height(32)
        .margin({ top: '30%', bottom: '10%' })
        .backgroundColor('#FFFFFF')
        .borderRadius(16)
        .onClick(() => {
          postCardAction(this, {
            action: 'router',
            abilityName: 'WidgetEventRouterEntryAbility',
            params: {
              routerDetail: 'RouterFromCard'
            }
          });
        })
      }.width('100%').height('40%')
      .justifyContent(FlexAlign.Center)
    }
    .width('100%')
    .height('100%')
    .alignItems(HorizontalAlign.Start)
    .backgroundImage($r('app.media.CardEvent'))
    .backgroundImageSize(ImageSize.Cover)
  }
}
```

### 步骤3:UIAbility处理Router事件

**示例代码 - Router事件处理**:
```typescript
// entry/src/main/ets/widgetevententryability/WidgetEventRouterEntryAbility.ts
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
import { formBindingData, formInfo, formProvider } from '@kit.FormKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

const TAG: string = 'WidgetEventRouterEntryAbility';
const DOMAIN_NUMBER: number = 0xFF00;

export default class WidgetEventRouterEntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    this.handleFormRouterEvent(want, 'onCreate');
  }

  handleFormRouterEvent(want: Want, source: string): void {
    hilog.info(DOMAIN_NUMBER, TAG, `handleFormRouterEvent ${source}, Want: ${JSON.stringify(want)}`);
    
    if (want.parameters && want.parameters[formInfo.FormParam.IDENTITY_KEY] !== undefined) {
      let curFormId = want.parameters[formInfo.FormParam.IDENTITY_KEY].toString();
      let message: string = (JSON.parse(want.parameters?.params as string))?.routerDetail;
      
      hilog.info(DOMAIN_NUMBER, TAG, `UpdateForm formId: ${curFormId}, message: ${message}`);
      
      let formData: Record<string, string> = {
        'routerDetail': message + ' ' + source + ' UIAbility'
      };
      
      let formMsg = formBindingData.createFormBindingData(formData);
      
      formProvider.updateForm(curFormId, formMsg).then((data) => {
        hilog.info(DOMAIN_NUMBER, TAG, 'updateForm success.', JSON.stringify(data));
      }).catch((error: BusinessError) => {
        hilog.info(DOMAIN_NUMBER, TAG, 'updateForm failed.', JSON.stringify(error));
      });
    }
  }

  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(DOMAIN_NUMBER, TAG, 'onNewWant Want:', JSON.stringify(want));
    this.handleFormRouterEvent(want, 'onNewWant');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onWindowStageCreate');
    windowStage.loadContent('pages/Index', (err, data) => {
      if (err.code) {
        hilog.error(DOMAIN_NUMBER, TAG, 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }
      hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
    });
  }
}
```

### 步骤4:卡片页面实现 - 触发Call事件

**示例代码 - Call事件**:
```typescript
// entry/src/main/ets/widgetupdatecall/pages/WidgetUpdateCallCard.ets
let storageUpdateCall = new LocalStorage();
@Entry(storageUpdateCall)
@Component
struct WidgetUpdateCallCard {
  @LocalStorageProp('formId') formId: string = '12400633174999288';
  @LocalStorageProp('calleeDetail') calleeDetail: ResourceStr = $r('app.string.init');
  
  build() {
    Column() {
      Column() {
        Text(this.calleeDetail)
          .fontColor('#FFFFFF')
          .opacity(0.9)
          .fontSize(14)
          .margin({ top: '8%', left: '10%' })
      }.width('100%').height('50%')
      .alignItems(HorizontalAlign.Start)
      
      Row() {
        Button() {
          Text($r('app.string.CalleeJumpLabel'))
            .fontColor('#45A6F4')
            .fontSize(12)
        }
        .width(120)
        .height(32)
        .margin({ top: '30%', bottom: '10%' })
        .backgroundColor('#FFFFFF')
        .borderRadius(16)
        .onClick(() => {
          postCardAction(this, {
            action: 'call',
            abilityName: 'WidgetCalleeEntryAbility',
            params: {
              method: 'funA',
              formId: this.formId,
              calleeDetail: 'CallFrom'
            }
          });
        })
      }.width('100%').height('40%')
      .justifyContent(FlexAlign.Center)
    }
    .width('100%')
    .height('100%')
    .alignItems(HorizontalAlign.Start)
    .backgroundImage($r('app.media.CardEvent'))
    .backgroundImageSize(ImageSize.Cover)
  }
}
```

### 步骤5:UIAbility处理Call事件

**示例代码 - Call事件处理**:
```typescript
// entry/src/main/ets/widgetcalleeentryability/WidgetCalleeEntryAbility.ts
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
import { formBindingData, formProvider } from '@kit.FormKit';
import { rpc } from '@kit.IPCKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

const TAG: string = 'WidgetCalleeEntryAbility';
const DOMAIN_NUMBER: number = 0xFF00;
const MSG_SEND_METHOD: string = 'funA';
const CONST_NUMBER_1: number = 1;

class MyParcelable implements rpc.Parcelable {
  num: number;
  str: string;
  
  constructor(num: number, str: string) {
    this.num = num;
    this.str = str;
  };
  
  marshalling(messageSequence: rpc.MessageSequence): boolean {
    messageSequence.writeInt(this.num);
    messageSequence.writeString(this.str);
    return true;
  };
  
  unmarshalling(messageSequence: rpc.MessageSequence): boolean {
    this.num = messageSequence.readInt();
    this.str = messageSequence.readString();
    return true;
  };
}

let funACall = (data: rpc.MessageSequence): MyParcelable => {
  let params: Record<string, string> = JSON.parse(data.readString());
  
  if (params.formId !== undefined) {
    let curFormId: string = params.formId;
    let message: string = params.calleeDetail;
    
    hilog.info(DOMAIN_NUMBER, TAG, `UpdateForm formId: ${curFormId}, message: ${message}`);
    
    let formData: Record<string, string> = {
      'calleeDetail': message
    };
    
    let formMsg: formBindingData.FormBindingData = formBindingData.createFormBindingData(formData);
    
    formProvider.updateForm(curFormId, formMsg).then((data) => {
      hilog.info(DOMAIN_NUMBER, TAG, `updateForm success. ${JSON.stringify(data)}`);
    }).catch((error: BusinessError) => {
      hilog.error(DOMAIN_NUMBER, TAG, `updateForm failed: ${JSON.stringify(error)}`);
    });
  }
  
  return new MyParcelable(CONST_NUMBER_1, 'aaa');
};

export default class WidgetCalleeEntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    try {
      this.callee.on(MSG_SEND_METHOD, funACall);
    } catch (error) {
      hilog.error(DOMAIN_NUMBER, TAG, `${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`);
    }
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onWindowStageCreate');
    windowStage.loadContent('pages/Index', (err, data) => {
      if (err.code) {
        hilog.error(DOMAIN_NUMBER, TAG, 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }
      hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
    });
  }
}
```

### 步骤6:错误处理

**错误处理代码**:
```typescript
import { BusinessError } from '@kit.BasicServicesKit';

async function updateFormWithErrorHandling(formId: string, formData: Record<string, string>): Promise<void> {
  try {
    let formMsg = formBindingData.createFormBindingData(formData);
    await formProvider.updateForm(formId, formMsg);
    console.info('updateForm success');
  } catch (error) {
    const businessError = error as BusinessError;
    switch (businessError.code) {
      case 16501001:
        console.error('The ID of the form to be operated does not exist');
        break;
      case 16501003:
        console.error('The form cannot be operated by the current application');
        break;
      case 16500050:
        console.error('IPC connection error, retry later');
        break;
      case 16500060:
        console.error('Service connection error');
        break;
      case 401:
        console.error('Parameter error, check formId and formData');
        break;
      default:
        console.error(`Unknown error: ${businessError.code}, message: ${businessError.message}`);
    }
  }
}
```

### 步骤7:降级处理

**降级处理代码**:
```typescript
async function handleFormEventWithFallback(want: Want): Promise<void> {
  const formId = want.parameters?.[formInfo.FormParam.IDENTITY_KEY]?.toString();
  
  if (!formId) {
    console.warn('No formId found in want parameters');
    return;
  }
  
  try {
    const params = JSON.parse(want.parameters?.params as string);
    const formData = processData(params);
    await updateFormWithErrorHandling(formId, formData);
  } catch (error) {
    console.error('Failed to process form event, using fallback strategy');
    
    // 降级方案:使用默认数据更新卡片
    const fallbackData = {
      'status': 'Update Failed',
      'timestamp': new Date().toLocaleTimeString()
    };
    
    try {
      await formProvider.updateForm(formId, formBindingData.createFormBindingData(fallbackData));
    } catch (fallbackError) {
      console.error('Fallback update also failed:', (fallbackError as BusinessError).message);
    }
  }
}

function processData(params: Record<string, string>): Record<string, string> {
  // 数据处理逻辑
  return {
    'data': params.message || 'Default Message',
    'updateTime': new Date().toLocaleTimeString()
  };
}
```

## 错误码说明

| 错误码 | 说明 | 解决方法 |
|-------|------|---------|
| 401 | 参数错误:必填参数未指定、参数类型错误或参数校验失败 | 检查formId是否为字符串、formData是否为有效对象、params是否为JSON格式 |
| 16500050 | IPC连接错误 | 检查系统服务状态,延迟重试或重启应用 |
| 16500060 | 服务连接错误 | 检查FormKit服务是否正常运行,重启设备 |
| 16500100 | 获取配置信息失败 | 检查form_config.json配置文件是否正确 |
| 16501000 | 内部功能错误 | 检查代码逻辑,捕获异常并记录日志 |
| 16501001 | 卡片ID不存在 | 验证formId是否有效,检查卡片是否已删除 |
| 16501002 | 卡片数量超过最大限制 | 减少加桌卡片数量,清理不需要的卡片 |
| 16501003 | 当前应用无法操作该卡片 | 检查卡片是否属于当前应用,确认包名匹配 |
| 16501011 | 卡片不支持此操作 | 检查卡片类型是否支持该操作,确认API版本 |

## 编译和修复问题

### 依赖声明
```json
{
  "dependencies": {
    "@kit.AbilityKit": "latest",
    "@kit.ArkUI": "latest",
    "@kit.FormKit": "latest",
    "@kit.BasicServicesKit": "latest",
    "@kit.IPCKit": "latest",
    "@kit.PerformanceAnalysisKit": "latest"
  }
}
```

### 环境要求
- DevEco Studio:3.1及以上版本
- HarmonyOS SDK:API version 9及以上
- ArkTS:支持Stage模型
- 设备:支持卡片功能的HarmonyOS设备

### 常见编译问题

**问题1:postCardAction未定义**
```
Error: 'postCardAction' is not defined
```
**解决方法**:postCardAction是全局接口,无需导入,直接调用即可。确保在卡片页面中使用。

**问题2:formProvider导入错误**
```
Error: Cannot find module '@kit.FormKit'
```
**解决方法**:检查项目SDK版本是否支持FormKit,更新SDK或检查导入路径。

**问题3:权限未配置**
```
Error: Permission denied for call event
```
**解决方法**:在module.json5中添加ohos.permission.KEEP_BACKGROUND_RUNNING权限。

**问题4:UIAbility启动模式错误**
```
Error: Call event only supports singleton UIAbility
```
**解决方法**:将处理call事件的UIAbility的launchType设置为"singleton"。

**问题5:卡片数据超过限制**
```
Error: Form data exceeds size limit
```
**解决方法**:API version 20+数据总大小不超过10MB,图片不超过20张。减少数据量或图片数量。

## 常见问题与解决方法

### Q1:router事件无法拉起UIAbility
**原因**:UIAbility未正确配置或abilityName错误
**解决方法**:
- 检查module.json5中UIAbility配置
- 确认abilityName与配置文件一致
- 检查UIAbility是否在当前应用中定义
- 确认bundleName和moduleName正确

### Q2:call事件不触发回调方法
**原因**:callee监听未注册或method参数错误
**解决方法**:
- 确保在onCreate中注册callee监听
- 检查method参数与注册的方法名一致
- 确认UIAbility的launchType为singleton
- 检查权限配置是否正确

### Q3:updateForm更新失败
**原因**:formId无效或数据格式错误
**解决方法**:
- 验证formId是否为有效字符串
- 检查formData是否符合FormBindingData格式
- 确认卡片未被删除或销毁
- 检查数据大小是否超过限制

### Q4:卡片点击无响应
**原因**:onClick事件未正确触发postCardAction
**解决方法**:
- 检查onClick回调是否正确实现
- 确认postCardAction参数完整(action、abilityName、params)
- 检查卡片页面组件是否正确绑定事件
- 验证卡片是否正常运行状态

### Q5:后台运行权限被拒绝
**原因**:系统权限管理限制
**解决方法**:
- 检查权限是否在module.json5中声明
- 确认应用类型是否支持后台运行
- 考虑使用router事件替代call事件
- 引导用户手动授予权限

### Q6:卡片刷新延迟过长
**原因**:UIAbility处理耗时操作
**解决方法**:
- 将耗时操作移至异步任务
- 减少数据处理逻辑复杂度
- 使用缓存数据快速刷新
- 避免在call事件中执行超过5秒的操作

## 输出结果报告

执行完成后输出以下信息:

```json
{
  "status": "success",
  "eventType": "router | call",
  "formId": "卡片标识",
  "abilityName": "UIAbility名称",
  "updateResult": {
    "formData": "更新的数据内容",
    "updateTime": "刷新时间戳"
  },
  "apiUsed": [
    "postCardAction",
    "formBindingData.createFormBindingData",
    "formProvider.updateForm"
  ],
  "permissions": ["ohos.permission.KEEP_BACKGROUND_RUNNING"],
  "constraints": {
    "dataSize": "不超过10MB (API version 20+)",
    "imageCount": "不超过20张 (API version 20+)",
    "uiabilityMode": "singleton for call event"
  }
}
```

## 参考文档

- [通过router或call事件刷新卡片内容开发指南](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-ui-widget-event-uiability)
- [postCardAction API参考](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-postcardaction)
- [formProvider.updateForm API参考](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-app-form-formprovider)
- [formBindingData API参考](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-app-form-formbindingdata)
- [UIAbility组件启动模式](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/uiability-launch-type)
- [应用权限列表](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/permissions-for-all)

## 完整示例代码

- [Router事件卡片示例](assets/widget_update_router_card.ets)
- [Router事件UIAbility示例](assets/widget_event_router_entry_ability.ts)
- [Call事件卡片示例](assets/widget_update_call_card.ets)
- [Call事件UIAbility示例](assets/widget_callee_entry_ability.ts)
- [权限配置示例](assets/module.json5)

## 测试用例

### 正向测试用例
- [Router事件触发并刷新卡片](tests/test_router_event_positive.ts):验证router事件正常触发UIAbility并更新卡片
- [Call事件触发并刷新卡片](tests/test_call_event_positive.ts):验证call事件在后台正常处理并更新卡片
- [参数传递验证](tests/test_params_passing.ts):验证params参数正确传递到UIAbility

### 边界测试用例
- [大数据刷新测试](tests/test_large_data.ts):测试接近10MB数据限制的刷新
- [最大图片数量测试](tests/test_max_images.ts):测试20张图片的刷新限制
- [多卡片并发刷新](tests/test_concurrent_forms.ts):测试同时刷新多个卡片

### 异常测试用例
- [无效formId测试](tests/test_invalid_formid.ts):测试formId不存在时的错误处理
- [权限缺失测试](tests/test_missing_permission.ts):测试缺少后台运行权限时的处理
- [参数错误测试](tests/test_invalid_params.ts):测试params格式错误时的处理
- [UIAbility不存在测试](tests/test_missing_ability.ts):测试abilityName错误时的处理

Attribution

IsKenKenYaIsKenKenYa
View sourceMore from IsKenKenYa →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

284072 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2192 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →