更新记录

1.0.0(2026-09-30)

新版提交


平台兼容性

uni-app(5.07)

Vue2 Vue2插件版本 Vue3 Vue3插件版本 Chrome Safari app-vue app-vue插件版本 app-nvue app-nvue插件版本 Android iOS 鸿蒙
√ 1.0.0 √ 1.0.0 × × √ 1.0.0 √ 1.0.0 - - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

uni-app x(5.07)

Chrome Safari Android iOS 鸿蒙 微信小程序
× × 7.0 12 × ×

csj-short-drama

穿山甲短剧(内容 SDK) 的 UTS 插件,为 uni-app x App 端提供短剧内容接入与广告解锁能力。

插件只提供 API,不提供列表 UI 组件;业务侧自行实现首页、频道、搜索、收藏、观看记录等页面,并通过插件的 open() / openDraw() / openHome() 打开由穿山甲原生渲染的播放页 / 滑滑流 / 聚合页。

支持能力

能力 Android iOS 说明
初始化 / 启动(含广告 SDK 自动初始化) ✅ ✅ 插件内部完成广告 SDK → 内容 SDK 的初始化时序
短剧列表 / 推荐 / 分类 / 搜索 / 详情 ✅ ✅ 对应官方 IDJXService / DJXPlayletManager
观看记录 / 收藏列表 / 清空观看记录 ✅ ✅ —
点赞、取消点赞、收藏、取消收藏 ✅ ❌ iOS 原生未公开该接口,调用返回 -3,需业务侧自行维护状态
分集解锁状态查询 ✅ ⚠️ iOS 无独立接口,返回空列表;解锁信息随 getInfo() 的 rawData 下发
播放页 open() ✅ ✅ 原生全屏播放页
滑滑流 openDraw() ✅ ✅ 沉浸式竖滑流
聚合页 openHome() ✅ ✅ 原生短剧聚合页
SDK 广告解锁(unlockAdMode: 'sdk') ✅ ✅ 广告位来自 SDK_Setting.json
自定义广告解锁(unlockAdMode: 'custom') ✅ ✅ 业务侧自己播激励视频,回传 completeUnlock()
解锁记录绑定业务账号 ✅ ✅ bindUnlockRecord() / unbindUnlockRecord()

平台与版本

项 值
支持框架 uni-app x(App 端);不支持浏览器、小程序、鸿蒙
Android minSdkVersion 24,官方 SDK com.pangle.cn:pangrowth-djx-sdk-lite:3.0.0.2
iOS deploymentTarget 12.0,CocoaPods PangrowthX/shortplay 2.9.0.6 + TTSDKFramework/{LivePull,Player-SR} 1.46.2.7-premium
HBuilderX ^5.25(建议 5.26 及以上)
调试方式 必须自定义基座或云打包 App;标准基座不可用

接入前必读

  1. 仅 App 真机环境:插件是原生扩展,浏览器、小程序、标准基座都无法运行。改完插件代码后必须重新制作自定义基座。
  2. 必须先开通穿山甲短剧内容能力:在穿山甲后台「内容输出 → 接入管理」录入应用并下载 SDK_Setting.json,否则初始化会报 04016。
  3. 必须勾选穿山甲广告模块:manifest.json → App 模块配置 → uni-ad(穿山甲 / GroMore)。 插件通过官方广告 SDK 的类(Android TTAdSdk、iOS BUAdSDKManager)初始化广告 SDK,这些类由 uni-ad 的穿山甲模块提供; 未勾选时插件会抛出 adInitFailed(Android -7004:TTAdSdk class not found)。
  4. 短剧只支持广告解锁:不支持 IAP、会员付费,也不允许把全部剧集设为免费。 免费集数上限为 min(20 集, 全剧前 20%),一次激励视频最多解锁 10 集。违反规则会被平台强制回退到兜底广告,严重会被封禁。
  5. 建议激励视频瀑布流中包含穿山甲广告且填充率 > 6%,详见官方规则。
  6. 双端 SDK_Setting.json 是两份不同的文件:Android 录包名、iOS 录 Bundle ID,不能互相复制。
  7. Android 运行时不要勾选 HBuilderX 的「清理构建缓存」,否则可能出现运行时报错。
  8. iOS 的插件资源要与构建产物版本一致:utssdk/app-ios/Resources/ 下的 CSJAdSDK.bundle 等资源带版本号, 与本次打包实际链接的广告 SDK 版本不一致会导致 error_code=2。重新打包后请运行 scripts/verify-ios-resources.sh 校验(见 iOS 资源版本一致性)。
  9. 隐私合规:广告 SDK 初始化会读取设备信息,请在用户同意隐私政策之后再调用 createShortDrama()。

目录结构

uni_modules/csj-short-drama/
├── package.json
├── readme.md
├── scripts/
│   └── verify-ios-resources.sh        # iOS 资源版本一致性校验(见文末)
└── utssdk/
    ├── interface.uts                  # 公共类型与接口定义(API 契约)
    ├── app-android/
    │   ├── config.json                # Maven 依赖:pangrowth-base / pangrowth-djx-sdk-lite
    │   ├── AndroidManifest.xml        # 权限声明 + 组件宿主 Activity
    │   ├── DJXNativeBridge.kt         # 官方 SDK 调用桥接层
    │   ├── DJXHostActivity.kt         # 聚合页 / 滑滑流 / 播放页 的 Fragment 容器
    │   ├── res/values/styles.xml
    │   ├── index.uts                  # UTS 层实现
    │   └── assets/SDK_Setting.json    # ⚠️ 必须替换为当前应用的后台配置
    └── app-ios/
        ├── config.json                # CocoaPods 依赖 + 系统 framework 链接
        ├── DramaModuleBridge.swift    # 原生桥接层(含广告 SDK 反射初始化)
        ├── index.uts                  # UTS 层实现
        └── Resources/                 # ⚠️ 整个目录会被平铺拷贝到 .app 根目录
            ├── SDK_Setting.json       # ⚠️ 必须替换为当前应用的后台配置
            ├── *.metallib             # 播放器 Metal 着色器(缺失会导致一进播放器就闪退)
            ├── bmf_hydra/             # BMF 效果框架着色器
            ├── DJXSDK.bundle          # 短剧内容 UI 资源(封面 / 图标 / 文案)
            ├── CSJAdSDK.bundle        # 穿山甲广告 UI 资源(含 version.txt,版本必须与构建产物一致)
            ├── VeLive.bundle          # 直播 PrivacyInfo
            └── APMInsight*.bundle / Rangers*.bundle   # APM / 埋点资源

配置文件

Android

把当前 Android 应用对应的 SDK_Setting.json 放到:

uni_modules/csj-short-drama/utssdk/app-android/assets/SDK_Setting.json

检查三项:

  • init.site_id 是当前 Android 应用的穿山甲媒体 ID;
  • license_config[].PackageName 与工程 Android 包名一致;
  • 后台已为该应用开通短剧功能并配置短剧广告位。

iOS

把当前 iOS 应用对应的 SDK_Setting.json 放到:

uni_modules/csj-short-drama/utssdk/app-ios/Resources/SDK_Setting.json

检查三项:

  • init.site_id 是当前 iOS 应用的穿山甲媒体 ID;
  • license_config[].BundleId 与工程 Bundle ID 一致;
  • 后台已为该应用开通短剧功能并配置短剧广告位。

Resources/ 目录里除 SDK_Setting.json 之外的文件都不要手改,它们必须与本次打包实际使用的 SDK 版本一致,详见 iOS 资源版本一致性。

adSiteId 与 adpid

名称 含义 是否需要传给插件
adSiteId 穿山甲广告 SDK 媒体 ID(= SDK_Setting.json 的 init.site_id) 可选。不传时插件读 SDK_Setting.json;当前仅 iOS 生效,Android 始终读 assets/SDK_Setting.json
adpid 激励视频广告位 ID 只有 unlockAdMode: 'custom' 时业务侧自己使用,不需要传给 createShortDrama()

同一个 SDK_Setting.json 里两者都有:init.site_id 是媒体 ID(广告 SDK 用),短剧解锁广告位由后台配置下发。

快速开始

1. 导入并创建实例

import { createShortDrama } from '@/uni_modules/csj-short-drama'
import type { ShortDrama, ShortDramaError, ShortDramaListResult } from '@/uni_modules/csj-short-drama'

let shortDrama: ShortDrama | null = null

function getShortDrama(): ShortDrama {
  const current = shortDrama
  if (current != null) return current

  const sdk = createShortDrama({ debug: true })
  sdk.onError((err: ShortDramaError) => {
    console.error('短剧插件错误', err.code, err.message)
  })
  shortDrama = sdk
  return sdk
}

关于初始化时序:官方要求「广告 SDK 初始化成功后才能初始化内容 SDK」。本插件已把这一时序封装在内部:

createShortDrama()
   ↓  1) 广告 SDK(Android TTAdSdk / iOS BUAdSDKManager,appId = init.site_id)
   ↓     成功(失败则 15s / 10s 看门狗兜底,交给官方 SDK 报出明确错误码)
   ↓  2) 内容 SDK DJXSdk / DJXManager init + start
   ↓  3) 触发 onLoad;此前发起的 open* / get* 调用会被排队或提示稍后重试
  • 不需要业务侧先调用 uni.createRewardedVideoAd() 之类的广告 API 来「预热」广告 SDK。
  • 推荐在 App 启动后(例如首页 onLoad)就先 createShortDrama(),把 SDK 启动的几秒钟提前消化掉。
  • 启动中的调用行为差异:iOS 会自动排队,启动成功后补跑本次调用;Android 会立即回调 -1 (消息里提示"正在等待广告SDK初始化,通常几秒内完成,请稍后重试")并自动重排启动,业务侧稍后重试即可。

2. 拉列表并打开播放页

function loadRecommend() {
  getShortDrama().getRecommendedList({ page: 1, pageSize: 20 }, (res: ShortDramaListResult) => {
    // res.list: Array<ShortDramaInfo>
    console.log('推荐列表', res.list.length)
  }, (err: ShortDramaError) => {
    console.error('拉取失败', err.code, err.message)
  })
}

function playOne(dramaId: number, episode: number) {
  getShortDrama().open({
    dramaId: dramaId,
    startEpisode: episode,
    freeEpisodeCount: 1,
    unlockEpisodeCount: 1,
    unlockAdMode: 'sdk'
  }, () => {
    console.log('播放页已打开')
  }, (err: ShortDramaError) => {
    console.error('打开失败', err.code, err.message)
  })
}

常用能力示例

列表 / 分类 / 搜索

const sdk = getShortDrama()

// 全量列表
sdk.getList({ page: 1, pageSize: 20, order: 'default' }, onList, onFail)

// 推荐列表
sdk.getRecommendedList({ page: 1, pageSize: 20 }, onList, onFail)

// 分类列表(分类名由 getCategories 下发)
sdk.getCategories((res: ShortDramaCategoryListResult) => {
  console.log('分类', res.list.map((item) => item.name))
}, onFail)

// 按分类取剧
sdk.getListByCategory({ category: '霸总', page: 1, pageSize: 20 }, onList, onFail)

// 搜索
sdk.search({ keyword: '总裁', fuzzy: true, page: 1, pageSize: 20 }, onList, onFail)

// 按 ID 查详情(dramaId 与 dramaIds 二选一)
sdk.getInfo({ dramaId: 12345 }, onList, onFail)
sdk.getInfo({ dramaIds: [12345, 67890] }, onList, onFail)

观看记录 / 收藏 / 清空记录

sdk.getWatchHistory({ page: 1, pageSize: 20 }, onList, onFail)
sdk.getFavorites({ page: 1, pageSize: 20 }, onList, onFail)
sdk.clearWatchHistory(() => { console.log('已清空观看记录') }, onFail)

点赞与收藏(仅 Android 生效)

sdk.like({ dramaId: 12345, episode: 1 }, () => {}, onFail)
sdk.unlike({ dramaId: 12345, episode: 1 }, () => {}, onFail)
sdk.favorite({ dramaId: 12345, episode: 1 }, () => {}, onFail)
sdk.unfavorite({ dramaId: 12345, episode: 1 }, () => {}, onFail)

iOS 原生头文件未公开点赞 / 收藏接口,这四个方法在 iOS 上会回调 -3,请业务侧自行维护状态。

分集解锁状态(Android)

sdk.getEpisodeUnlockStatus({ dramaId: 12345, freeEpisodeCount: 1 }, (res: ShortDramaEpisodeUnlockStatusResult) => {
  const locked = res.list.filter((item) => item.locked).map((item) => item.episodeIndex)
  console.log('锁定集', locked)
}, onFail)

iOS 无独立接口,返回空列表;解锁信息随 getInfo() 返回的 rawData 一并下发。

打开播放页 open()

sdk.open({
  dramaId: 12345,
  startEpisode: 1,            // 起播集数,默认 1
  freeEpisodeCount: 1,        // 前置免费集数,默认 1(上限 20 且不超过全剧前 20%)
  unlockEpisodeCount: 1,      // 一次激励视频解锁集数,默认 1(上限 10)
  unlockAdMode: 'sdk',        // 'sdk' 用 SDK_Setting.json 广告;'custom' 业务侧自己播广告
  hideTopInfo: false,         // 隐藏顶部信息
  hideBottomInfo: false,      // 隐藏底部信息
  hideLikeButton: false,      // 隐藏点赞按钮
  hideFavorButton: false,     // 隐藏收藏按钮
  hideMore: false,            // 隐藏更多按钮
  hideBack: false,            // 隐藏返回按钮
  hideRewardDialog: false,    // 隐藏激励广告确认弹窗
  topOffset: 0,               // 顶部偏移 px(Android)
  bottomOffset: -1            // 底部偏移 px(Android)
}, onOpen, onFail)

打开滑滑流 openDraw()

sdk.openDraw({
  channelType: 'recommendTheater',   // 'recommend' | 'theater' | 'recommendTheater'
  hideChannelName: false,
  hideDramaInfo: false,              // Android
  hideDramaEnter: false,
  enableRefresh: true,               // 仅 Android 生效
  hideClose: false,
  dramaFree: 1,                      // 滑滑流免费集数
  topDramaId: 0,                     // 置顶短剧,0 表示不指定
  freeEpisodeCount: 1,               // iOS 忽略该项,使用 dramaFree
  unlockEpisodeCount: 1,
  unlockAdMode: 'sdk'
}, onOpen, onFail)

打开原生聚合页 openHome()

sdk.openHome({
  showChangeBtn: true,      // 换一换按钮(当前 Android 生效)
  showPageTitle: true,
  showBackBtn: true,
  topOffset: 0,             // 顶部偏移 px(当前 Android 生效)
  topDramaId: 0,
  freeEpisodeCount: 1,
  unlockEpisodeCount: 1,
  unlockAdMode: 'sdk'
}, onOpen, onFail)

自定义广告解锁(unlockAdMode: 'custom')

默认的 'sdk' 模式不需要监听解锁事件,也不需要回传任何东西。只有 'custom' 模式才需要业务侧自己播激励视频, 并把结果回传,否则解锁任务会一直挂起。

解锁事件分三段:unlockStart(开始)→ unlockRequired(需要业务侧展示广告)→ unlockEnd(结束)。

import type { ShortDramaUnlockEvent, ShortDramaError } from '@/uni_modules/csj-short-drama'

let rewardAd: RewardedVideoAd | null = null
let pendingTaskId = ''
let rewardShownTaskId = ''

function completePending(success: boolean, extra: UTSJSONObject) {
  if (pendingTaskId.length == 0) return
  getShortDrama().completeUnlock({ taskId: pendingTaskId, success: success, extra: extra })
  pendingTaskId = ''
  rewardShownTaskId = ''
}

function ensureRewardAd(): RewardedVideoAd {
  const current = rewardAd
  if (current != null) return current
  const created = uni.createRewardedVideoAd({ adpid: '你的激励视频广告位 ID' })
  rewardAd = created
  // 广告实例的生命周期回调只注册一次,不要放进 onUnlockEvent 里
  created.onLoad((_res: any) => {
    if (pendingTaskId.length == 0 || rewardShownTaskId == pendingTaskId) return
    rewardShownTaskId = pendingTaskId
    // 广告真实展示「之前」通知短剧 SDK
    getShortDrama().notifyUnlockAdWillShow({ taskId: pendingTaskId })
    created.show()
  })
  created.onClose((res: RewardedVideoAdClose) => {
    completePending(res.isEnded == true, { isEnded: res.isEnded } as UTSJSONObject)
  })
  created.onError((err: any) => {
    // 加载/展示失败也要结束任务,否则解锁流程会卡住
    completePending(false, { error: err } as UTSJSONObject)
  })
  return created
}

getShortDrama().onUnlockEvent((event: ShortDramaUnlockEvent) => {
  if (event.type != 'unlockRequired') return
  pendingTaskId = event.taskId
  rewardShownTaskId = ''
  ensureRewardAd().load()
})

要点:

  • taskId 必须来自当前 unlockRequired 事件;同一次任务不要重复回传。
  • 用户跳过广告、广告加载失败、展示失败,都要用 completeUnlock({ taskId, success: false }) 结束任务。
  • 广告真实曝光时回传 CPM(notifyUnlockAdWillShow({ taskId, cpm }) 与 completeUnlock({ taskId, success, cpm })); 拿不到时传空字符串 ''。CPM 长期为空会被短剧 SDK 强制切换成 SDK 直出广告,并屏蔽自定义解锁逻辑。
  • 自定义瀑布流必须包含穿山甲广告并产生真实曝光。

解锁记录绑定业务账号

有账号体系时,登录成功后由业务服务端用穿山甲后台的 server key 生成签名串 (格式 nonce=...&ouid=...&timestamp=...&sign=...),客户端只传这个串。不要把 server key 下发或保存在客户端。

// params 由业务服务端返回,ouid 为稳定的业务账号 ID
getShortDrama().bindUnlockRecord({ params: serverSignedParams }, (res) => {
  console.log('绑定成功', res.bound, res.extra)
}, (err: ShortDramaError) => {
  console.error('绑定失败', err.code, err.message)
})

// 账号切换:先等旧账号解绑成功,再绑定新账号
getShortDrama().unbindUnlockRecord(() => {
  // 再调用 bindUnlockRecord({ params: newAccountParams })
}, onFail)

// 查询当前是否已绑定
const bound: boolean = getShortDrama().isUnlockRecordBound()

建议在读取解锁状态或打开播放页之前完成绑定;未绑定时按游客处理,解锁记录可能与设备关联。 只在业务账号真实退出登录时调用 unbindUnlockRecord(),关闭播放页或 destroy() 不应解绑。

API 参考

createShortDrama(options?)

参数 类型 默认 说明
adSiteId string '' 穿山甲广告 SDK 媒体 ID;不传时读取 SDK_Setting.json 的 init.site_id。当前仅 iOS 生效
debug boolean false 打开 SDK 调试日志
teenagerMode boolean false 青少年模式(开启后不返回短剧内容)

ShortDrama 方法

方法 说明
getList(options, success?, fail?) 全量短剧列表
getRecommendedList(options, success?, fail?) 推荐短剧列表
getInfo(options, success?, fail?) 按 dramaId / dramaIds 查询短剧信息
getCategories(success?, fail?) 分类列表
getListByCategory(options, success?, fail?) 按分类取剧
search(options, success?, fail?) 搜索短剧
getWatchHistory(options, success?, fail?) 观看记录
getFavorites(options, success?, fail?) 收藏列表
clearWatchHistory(success?, fail?) 清空观看记录
getEpisodeUnlockStatus(options, success?, fail?) 分集解锁 / 锁定状态(iOS 返回空列表)
like / unlike(options, success?, fail?) 点赞 / 取消点赞(iOS 返回 -3)
favorite / unfavorite(options, success?, fail?) 收藏 / 取消收藏(iOS 返回 -3)
open(options, success?, fail?) 打开原生播放页
openDraw(options, success?, fail?) 打开原生滑滑流
openHome(options, success?, fail?) 打开原生聚合页
bindUnlockRecord(options, success?, fail?) 绑定业务账号的解锁记录
unbindUnlockRecord(success?, fail?) 解绑业务账号
isUnlockRecordBound() 是否已绑定
notifyUnlockAdWillShow(options) 通知「业务侧激励视频即将展示」(自定义解锁)
completeUnlock(options) 回传业务侧解锁结果(自定义解锁)
destroy() 释放实例,清空全部事件监听与排队调用
onLoad / offLoad SDK 启动完成事件
onError / offError 错误事件
onPlayEvent / offPlayEvent 播放页事件
onDrawEvent / offDrawEvent 滑滑流事件
onHomeEvent / offHomeEvent 聚合页事件
onAdEvent / offAdEvent 广告事件
onUnlockEvent / offUnlockEvent 解锁事件

offXxx(callback?) 是清空该通道的全部监听(原生闭包在不同平台无法做相等比较),不是精确移除单个回调。

Options

ShortDramaListOptions

字段 类型 默认 说明
page number 1 页码,从 1 开始
pageSize number 20 每页数量
order 'default' \| 'reverse' 'default' 排序

ShortDramaInfoOptions

字段 类型 说明
dramaId number \| string 单部短剧 ID,与 dramaIds 二选一
dramaIds Array<any> 短剧 ID 列表,与 dramaId 二选一

ShortDramaSearchOptions

字段 类型 默认 说明
keyword string — 必填,搜索关键词
fuzzy boolean true 是否模糊搜索
page / pageSize number 1 / 20 分页

ShortDramaCategoryListOptions

字段 类型 默认 说明
category string — 必填,分类名称,如「霸总」
page / pageSize number 1 / 20 分页
order 'default' \| 'reverse' 'default' 排序

ShortDramaEpisodeUnlockStatusOptions

字段 类型 默认 说明
dramaId number \| string — 必填
freeEpisodeCount number 0 前置免费观看集数

ShortDramaUserActionOptions

字段 类型 默认 说明
dramaId number \| string — 必填
episode number 1 集数

ShortDramaOpenOptions

字段 类型 默认 说明
dramaId number \| string — 必填
startEpisode number 1 起播集数
freeEpisodeCount number 1 前置免费集数(上限 20 且不超过全剧前 20%)
unlockEpisodeCount number 1 一次激励视频解锁集数(上限 10,不支持一次解锁全集)
unlockAdMode 'sdk' \| 'custom' 'sdk' 解锁广告来源
hideBack boolean false 隐藏返回按钮
hideTopInfo boolean false 隐藏顶部信息
hideBottomInfo boolean false 隐藏底部短剧信息
hideMore boolean false 隐藏更多按钮
hideLikeButton boolean false 隐藏点赞按钮
hideFavorButton boolean false 隐藏收藏按钮
hideRewardDialog boolean false 隐藏激励广告确认弹窗
topOffset number 0 顶部偏移 px(Android)
bottomOffset number -1 底部偏移 px(Android)

ShortDramaDrawOptions

字段 类型 默认 说明
channelType 'recommend' \| 'theater' \| 'recommendTheater' 'recommend' 频道类型
hideChannelName boolean false 隐藏频道名 / 顶部 tab
hideDramaInfo boolean false 隐藏底部短剧信息(Android)
hideDramaEnter boolean false 隐藏底部短剧入口
enableRefresh boolean true 下拉刷新(仅 Android 生效)
hideClose boolean false 隐藏关闭按钮
dramaFree number 1 滑滑流免费集数(iOS 用这个值,freeEpisodeCount 被忽略)
topDramaId number \| string 0 置顶短剧,0 表示不指定
freeEpisodeCount number 1 进入播放页后的免费集数(Android)
unlockEpisodeCount number 1 每次激励视频解锁集数
unlockAdMode 'sdk' \| 'custom' 'sdk' 解锁广告来源

ShortDramaHomeOptions

字段 类型 默认 说明
showChangeBtn boolean true 显示换一换按钮(Android)
showPageTitle boolean true 显示页面标题
showBackBtn boolean true 显示返回按钮
topOffset number 0 顶部偏移 px(Android)
topDramaId number \| string 0 置顶短剧
freeEpisodeCount number 1 进入播放页后的免费集数
unlockEpisodeCount number 1 每次激励视频解锁集数
unlockAdMode 'sdk' \| 'custom' 'sdk' 解锁广告来源

NotifyUnlockAdWillShowOptions / CompleteUnlockOptions

字段 类型 必填 说明
taskId string ✅ unlockRequired 事件返回的任务 ID
cpm string 否 广告 CPM,不传为 '';建议在真实曝光时回传
success(仅 completeUnlock) boolean ✅ 激励视频是否完整观看并允许本次解锁
extra(仅 completeUnlock) UTSJSONObject 否 透传给短剧 SDK 的附加信息

ShortDramaUnlockRecordBindOptions

字段 类型 说明
params string 服务端签名的绑定串,格式 nonce=...&ouid=...&timestamp=...&sign=...

返回值与数据类型

ShortDramaListResult

字段 类型 说明
list Array<ShortDramaInfo> 短剧列表
extra UTSJSONObject 原生 SDK 附加数据

ShortDramaInfo

字段 类型 说明
dramaId number 短剧 ID
title string 标题
coverUrl string 封面图
summary string 简介
categoryId / categoryName number / string 分类
currentEpisode number 当前集
totalEpisodes number 总集数
groupId number 短剧分组 / 合集 ID
unlockedEpisodeIndex number 已解锁到的集
styleType number 样式类型
durationSeconds number 时长(秒)
rawData UTSJSONObject 原生原始数据,官方 SDK 新增字段、iOS 解锁状态等从这里读

部分字段(groupId / styleType / durationSeconds 等)在个别原生版本上没有返回值,会取默认值 0; 新接入时建议先用 rawData 打印一次真实结构再决定用哪些字段。

ShortDramaCategoryListResult / ShortDramaCategoryInfo

字段 类型 说明
list Array<ShortDramaCategoryInfo> { name: string, rawData: UTSJSONObject }
extra UTSJSONObject 附加数据

ShortDramaEpisodeUnlockStatusResult / …Info

字段 类型 说明
list Array<{ episodeIndex: number, locked: boolean, rawData: UTSJSONObject }> 分集状态
extra UTSJSONObject 附加数据

ShortDramaUnlockRecordBindResult

字段 类型 说明
bound boolean 是否已完成绑定
extra UTSJSONObject 原生返回的附加信息(如 loginType)

ShortDramaError

字段 类型 说明
code number 错误码
message string 错误信息
detail UTSJSONObject 原生 SDK 附加信息(可能为空)

事件说明

事件 常见 type 说明
onLoad — SDK 启动完成,payload 形如 { stage: 'start', ... };注册时若已启动会立即补发一次
onError — 初始化失败(stage: 'error')或广告 SDK 失败(type: adInitFailed / adStartFailed)
onPlayEvent requestStart、requestSuccess、requestFail、play、pause、resume、completion、over、progress、close 播放页事件
onDrawEvent 同上 + load 滑滑流事件
onHomeEvent requestStart、requestSuccess、prepareFail、createFail、load、open、close 聚合页事件
onAdEvent request、requestFail、show、clicked、rewardVerify 广告事件
onUnlockEvent unlockStart、unlockRequired、unlockEnd 解锁事件,详见上文

事件对象通用字段:

字段 类型 说明
type string 事件类型
data UTSJSONObject 附加数据
drama ShortDramaInfo 当前短剧(onPlayEvent 提供,部分原生化生命周期事件可能为空)
code number 错误码,成功为 0
message string 错误 / 状态信息
getShortDrama().onLoad((res: UTSJSONObject) => { console.log('SDK 已启动', res) })
getShortDrama().onError((err: ShortDramaError) => { console.error('短剧错误', err.code, err.message) })
getShortDrama().onPlayEvent((event: ShortDramaPlayEvent) => { console.log('play', event.type, event.code) })

平台差异

项 Android iOS
adSiteId 参数 忽略,固定读 assets/SDK_Setting.json 的 init.site_id 生效,不传则读 Resources/SDK_Setting.json
点赞 / 收藏 / 取消 生效 回调 -3(原生未公开),业务侧自行维护
getEpisodeUnlockStatus() 真实返回分集状态 返回空列表,改从 getInfo().rawData 读取
openDraw().enableRefresh 生效 忽略(原生未暴露该字段)
openDraw().freeEpisodeCount 生效 忽略,iOS 使用 dramaFree
openHome().showChangeBtn / topOffset 生效 以 SDK 实际暴露的属性为准(插件会尝试写入,未暴露则忽略)
启动中的 API 调用 立即回调 -1 并自动重排启动,稍后重试 自动排队,启动成功后补跑
原生页面宿主 DJXHostActivity(Fragment 容器) 直接 present 原生 UIViewController

offXxx(callback?) 两个平台都已统一为「清空该通道全部监听」。

接入时需要改动的文件(改动说明)

必须改动

文件 / 位置 改什么
utssdk/app-android/assets/SDK_Setting.json 整体替换为当前 Android 应用在穿山甲后台下载的配置
utssdk/app-ios/Resources/SDK_Setting.json 整体替换为当前 iOS 应用在穿山甲后台下载的配置(与 Android 那份不同)
manifest.json → *.distribute.modules.uni-ad 必须按平台分开配置(写法见「注意事项」第 9 条):Android 需含 gm,否则插件反射 TTAdSdk 报 -7004;iOS 不能含 gm,否则 archive 报 Multiple commands produce .../TTSDK*.framework
manifest.json → app-android.distribute.packageName
manifest.json → app-ios.distribute.*(Bundle ID)
与穿山甲后台录入的包名 / Bundle ID 完全一致,否则报 04016
业务页面 自行实现短剧列表 UI、入口、搜索页、收藏页等(插件不含 UI)

不要改动

文件 原因
utssdk/app-ios/Resources/ 下除 SDK_Setting.json 外的文件 与本次打包链接的 SDK 版本一一对应;CSJAdSDK.bundle 版本不一致会让广告 SDK 直接初始化失败(error_code=2)
utssdk/app-ios/config.json 的 pod 版本 LivePull / Player-SR / shortplay 三者版本是互相咬合的,随手换版本会引发重复动态库(Multiple commands produce)或符号缺失
utssdk/app-ios/Resources/*.metallib 二进制着色器,与播放器 pod 版本绑定;缺失或换版本会导致一进播放器就闪退
utssdk/app-android/config.json 的 Maven 依赖 与官方 SDK 版本一致,改前请确认官方新版本号

需要重新打包的场景

改动 utssdk/ 下任何原生代码或资源(.kt / .swift / .json / .bundle / .metallib)后, 必须重新「制作自定义基座」或重新云打包;只改 .uvue 业务代码不需要。

注意事项

  1. 合规是硬约束,不是建议:短剧必须走广告解锁,且必须有真实广告曝光。免费集数 / 解锁集数由短剧 SDK 强校验, 规避会导致平台强制走兜底广告,严重会被封禁(官方规则)。
  2. 不要缓存短剧内容渲染:04005 短剧不存在 表示内容已下线,应实时拉取列表后再渲染。
  3. 失败必须收尾:自定义解锁在用户跳过广告、广告加载失败、展示失败时都要 completeUnlock({ success: false }), 否则当前剧集一直处于解锁中,用户无法继续。
  4. CPM 不能长期为空:空 CPM 会被 SDK 判定为异常,强制切回 SDK 直出广告并屏蔽自定义解锁。
  5. destroy() 的时机:页面 / 模块不再使用短剧实例时调用,清空事件监听;但不要在此时调 unbindUnlockRecord()。
  6. 权限(Android):插件在 AndroidManifest.xml 声明了 READ_PHONE_STATE、ACCESS_NETWORK_STATE、 ACCESS_WIFI_STATE、READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE(官方建议全部申请,有助于推荐效果与 ecpm), 并注册了 DJXHostActivity。上架前请把对应权限用途写进隐私政策。
  7. PrivacyInfo:iOS 侧已随 Resources/ 提供 VeLive.bundle / RangersAPMPrivacyInfo.bundle 等隐私清单, 请勿删除;App Store 提交时会读取。
  8. 调试建议:先用 createShortDrama({ debug: true }) 打开 SDK 日志,再结合 onError / onLoad 判断卡在哪一步。
  9. uni-ad 模块必须按平台分开配置(打包前务必确认): gm(穿山甲 GroMore)在 iOS 侧会把整套 TTSDKFramework(播放器内核)拉进 app 工程, 与插件自带的那份同输出路径双写,云打包 archive 阶段报 error: Multiple commands produce '.../UniAppX.app/Frameworks/<TTSDK 系>.framework'(一连 23 条)。 插件已自带广告与播放器依赖,正确写法是把两个平台分开:

    "app"         : { "distribute": { "modules": { "uni-ad": { "gdt": {}, "ks": {} } } } },
    "app-android" : { "distribute": { "modules": { "uni-ad": { "gm": {}, "gdt": {}, "ks": {} } } } },
    "app-ios"     : { "distribute": { "modules": { "uni-ad": { "gdt": {}, "ks": {} } } } }
    • Android 必须保留 gm:插件启动时会反射 TTAdSdk 初始化广告 SDK,缺少该类会报 -7004 TTAdSdk class not found。
    • iOS 必须去掉 gm:广告 SDK(Ads-CN)与播放器(TTSDKFramework)均已由插件自身提供,去掉后功能不受影响。
    • 若你的业务另外用到 uni-ad 的穿山甲(GroMore)渠道广告位,注意 iOS 侧将不可用; 仅用插件内的短剧解锁广告则无影响。

常见报错

错误码 原因 处理
04016 包名 / Bundle ID 与后台不匹配 替换 SDK_Setting.json,核对 license_config[].PackageName / BundleId 与工程一致
04023 sha1 不匹配 签名与后台录入的不一致;debug / release 签名需统一
04010 时间戳异常 设备时间被手动修改
04005 短剧不存在 内容已下线,实时拉取,不要缓存渲染
error_code: 2
广告sdk未初始化成功
① 未勾选穿山甲广告模块;② iOS 上 CSJAdSDK.bundle 版本与本次链接的广告 SDK 不一致 ① 勾选 uni-ad 穿山甲模块;② 跑 scripts/verify-ios-resources.sh 校验并同步资源
-1 参数错误,或短剧 SDK 尚未启动完成(Android) 启动中的调用稍后重试;建议在 App 启动时先 createShortDrama()
-3 iOS 端点赞 / 收藏接口未公开 业务侧自行维护点赞、收藏状态
-5 getInfo() 未提供 dramaId 或 dramaIds 至少传一个
-1001 iOS 未链接到 PangrowthDJX(pod 未装成功) 检查 utssdk/app-ios/config.json 的 PangrowthX/shortplay 是否解析成功
-1002 找不到 iOS 配置文件 / 内容为空 确认 Resources/SDK_Setting.json 存在且非空
-1003 iOS 配置文件不是合法 JSON 用后台下载的原文件替换,不要手工改格式
-7001 广告 SDK appId(init.site_id)读取失败 检查 assets/SDK_Setting.json 的 init.site_id
-7002 / -7003 广告 SDK 的 init / start 方法不存在 广告 SDK 版本异常,检查 uni-ad 模块是否勾选
-7004 找不到 TTAdSdk 类 未勾选穿山甲广告模块;在 manifest.json 勾选 uni-ad 后重打基座
-7005 / -7006 反射初始化广告 SDK 抛异常 查看 logcat 中原生堆栈,通常是广告模块版本冲突
-7007 广告 SDK start 回调失败 检查媒体 ID、网络、以及后台是否开通短剧能力

常见问题

Q:插件提供列表 UI 吗? 不提供。插件只有 API 与三个原生页面(播放页、滑滑流、聚合页),列表、搜索、收藏等页面需要业务侧自己写。

Q:默认 'sdk' 解锁需要传激励视频广告位 ID 吗? 不需要。广告位来自 SDK_Setting.json 的后台配置。只有 'custom' 模式才需要业务侧自己 uni.createRewardedVideoAd({ adpid })。

Q:'sdk' 和 'custom' 怎么选? 'sdk' 接入最简单,广告请求完全交给短剧 SDK;'custom' 适合已有自己广告体系(UniAd / 自有聚合)的业务, 但对应的瀑布流必须包含穿山甲广告,并且要完整回传展示与解锁结果,否则会被强制切回 SDK 直出广告。

Q:为什么调 API 立刻返回 -1? Android 上广告 SDK 尚未初始化完成(通常几秒)。插件已自动排队启动,稍后重试即可; 更稳妥的做法是在 App 启动时就 createShortDrama(),把启动时间提前。

Q:重装应用后为什么还保留解锁记录? 未绑定业务账号时,解锁记录与设备关联;调用 bindUnlockRecord() 绑定账号后,解锁权益跟随账号, 账号切换 / 退出登录由业务侧负责解绑与重绑。

Q:iOS 上点赞 / 收藏没有反应? iOS 原生未公开这两个接口,插件返回 -3,请在业务侧维护状态。

Q:iOS 播放页一打开就闪退,崩溃日志里有 MTLReportFailure / MTLLibraryBuilder? App 包根目录缺少播放器的 Metal 着色器(*.metallib)。确认 utssdk/app-ios/Resources/ 下的 *.metallib 没有被删, 然后重新制作自定义基座。详见 iOS 资源版本一致性。

Q:Android 运行时莫名报错? 不要勾选 HBuilderX 的「清理构建缓存」,并在改完插件后重新制作自定义基座。

Q:页面销毁时要做些什么? 调用 shortDrama.destroy() 清空事件监听,并把业务侧持有的 shortDrama 置空;destroy() 不负责解绑账号。

iOS 资源版本一致性(进阶)

这是本插件在 iOS 上最容易踩的坑,正式上线前请花 10 秒跑一次校验。

背景:短剧播放器与广告 SDK 在运行时会优先到 App 包根目录(Bundle.main) 找自己的资源 bundle。 插件的 utssdk/app-ios/Resources/ 会被 HBuilderX 平铺拷贝到 .app 根目录,因此这里的资源版本必须与 本次打包实际链接的 SDK 版本一致:

  • CSJAdSDK.bundle/version.txt 与链接进产物的广告 SDK 版本不一致 → 广告 SDK 初始化失败 → 内容 SDK 报 error_code=2;
  • *.metallib 缺失或版本不匹配 → 一进播放器 SIGABRT(MTLReportFailure)。

为什么会漂:PangrowthX/shortplay 只写了 Ads-CN/BUAdSDK >= 5.8.0.9,没有锁死版本, CocoaPods 每次打包会取「当时最新」的 Ads-CN,而插件自带的 bundle 是固定的。

校验方法(每次重新打自定义基座后执行):

cd uni_modules/csj-short-drama
./scripts/verify-ios-resources.sh                      # 默认读 ../../unpackage/debug/iOS_debug_vapor.ipa
./scripts/verify-ios-resources.sh /path/to/your.ipa    # 也可以指定 ipa

脚本会把 Resources/ 里每个文件与 ipa 内插件 framework 中的同名资源逐字节比对:

  • ✓ 一致;✗ 版本不一致 → 用本次构建产物(Payload/*.app/Frameworks/unimodule*.framework/) 里的同名资源覆盖 Resources/,再重新打包;
  • ⚠ 构建产物里有、插件 Resources 没有 → 该资源会缺失在 App 根目录,按需补进 Resources/;
  • 退出码非 0 表示校验失败(可接入 CI)。

⛔ 不要从别的工程、别的 pod 版本或 CocoaPods 缓存里随手拷 CSJAdSDK.bundle / *.metallib —— 版本对不上比不拷更糟。唯一正确的来源是本工程这一次的构建产物。

更新日志

v1.0.0(2026-09-29)

  • 首个版本:Android / iOS 双端完整实现(列表、推荐、分类、搜索、详情、观看记录、收藏、分集解锁状态)。
  • 三个原生页面:播放页 open()、滑滑流 openDraw()、聚合页 openHome()。
  • 两种解锁模式:SDK 广告解锁与业务侧自定义广告解锁(unlockStart / unlockRequired / unlockEnd 三段事件)。
  • 解锁记录绑定业务账号:bindUnlockRecord() / unbindUnlockRecord() / isUnlockRecordBound()。
  • 广告 SDK 由插件自动初始化(Android 反射 TTAdSdk、iOS 反射 BUAdSDKManager,appId 取 init.site_id, 分别带 15s / 10s 看门狗兜底),业务侧不必先调用 UniAd 广告 API。
  • iOS 启动中的调用自动排队补跑;Android 先自动重排启动并提示稍后重试。
  • iOS 侧随插件提供播放器 / 广告 SDK 所需的全部资源(*.metallib、DJXSDK.bundle、CSJAdSDK.bundle 等), 并提供 scripts/verify-ios-resources.sh 做版本一致性校验。

示例工程

pages/ 下提供 4 个可直接运行的场景页,覆盖主要接法:

页面 场景
pages/index/index.uvue 示例导航页(原生聚合页 / 自建聚合页 / 全屏滑滑流 三个入口)
pages/sdk-internal/index.uvue 原生聚合页 openHome() + SDK / 自定义解锁切换
pages/api-list/index.uvue 自建聚合页:列表 / 分类 / 搜索 / 收藏 / 观看记录 / 绑定解锁记录 / 打开播放页
pages/custom-ad/index.uvue 全屏滑滑流 openDraw() + 自定义激励视频解锁完整流程

场景页采用统一的自定义视觉规范(深色面板 + 描边式选项组,每页一套主题色), 仅用于演示 API 调用方式。页面结构与样式同插件功能完全解耦, 业务侧可整体替换为自己的设计规范,只需保留 createShortDrama() 的调用与事件绑定。

示例中的激励视频 adpid、SDK_Setting.json 均为示例应用配置,正式接入请全部替换成自己后台的配置。

相关文件

  • API 契约(类型定义):utssdk/interface.uts
  • iOS 资源一致性校验脚本:scripts/verify-ios-resources.sh
  • 双端原生实现:utssdk/app-android/(Kotlin)、utssdk/app-ios/(Swift)

隐私、权限声明

1. 本插件需要申请的系统权限列表:

网络、存储、设备信息(详见 AndroidManifest)

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

短剧内容与播放数据由穿山甲内容SDK处理

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

使用穿山甲广告SDK(需在 manifest.json 勾选穿山甲模块)

暂无用户评论。