@24jieqi/react-native-brayant-ad 0.1.34 → 0.1.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +213 -852
  2. package/android/src/main/java/com/brayantad/dy/banner/view/BannerAdView.java +7 -0
  3. package/android/src/main/java/com/brayantad/dy/feedAd/FeedAdViewManager.java +5 -0
  4. package/android/src/main/java/com/brayantad/dy/feedAd/view/FeedAdView.java +19 -4
  5. package/ios/PangleAdModule/BannerAd.m +9 -2
  6. package/ios/PangleAdModule/FeedAdView.h +5 -0
  7. package/ios/PangleAdModule/FeedAdView.m +36 -15
  8. package/ios/PangleAdModule/FeedAdViewManager.m +4 -0
  9. package/ios/PangleAdModule/PangleAdModule.h +0 -1
  10. package/ios/PangleAdModule/PangleAdModule.m +25 -47
  11. package/lib/commonjs/dy/api/AdManager.js +38 -4
  12. package/lib/commonjs/dy/api/AdManager.js.map +1 -1
  13. package/lib/commonjs/dy/api/FullScreenVideo.js +61 -3
  14. package/lib/commonjs/dy/api/FullScreenVideo.js.map +1 -1
  15. package/lib/commonjs/dy/api/RewardVideo.js +58 -3
  16. package/lib/commonjs/dy/api/RewardVideo.js.map +1 -1
  17. package/lib/commonjs/dy/api/SplashAd.js +64 -3
  18. package/lib/commonjs/dy/api/SplashAd.js.map +1 -1
  19. package/lib/commonjs/dy/component/BannerAd.js +71 -2
  20. package/lib/commonjs/dy/component/BannerAd.js.map +1 -1
  21. package/lib/module/dy/api/AdManager.js +38 -4
  22. package/lib/module/dy/api/AdManager.js.map +1 -1
  23. package/lib/module/dy/api/FullScreenVideo.js +62 -4
  24. package/lib/module/dy/api/FullScreenVideo.js.map +1 -1
  25. package/lib/module/dy/api/RewardVideo.js +59 -4
  26. package/lib/module/dy/api/RewardVideo.js.map +1 -1
  27. package/lib/module/dy/api/SplashAd.js +64 -3
  28. package/lib/module/dy/api/SplashAd.js.map +1 -1
  29. package/lib/module/dy/component/BannerAd.js +72 -3
  30. package/lib/module/dy/component/BannerAd.js.map +1 -1
  31. package/lib/typescript/src/dy/api/AdManager.d.ts.map +1 -1
  32. package/lib/typescript/src/dy/api/FullScreenVideo.d.ts +6 -0
  33. package/lib/typescript/src/dy/api/FullScreenVideo.d.ts.map +1 -1
  34. package/lib/typescript/src/dy/api/RewardVideo.d.ts +6 -0
  35. package/lib/typescript/src/dy/api/RewardVideo.d.ts.map +1 -1
  36. package/lib/typescript/src/dy/api/SplashAd.d.ts +6 -0
  37. package/lib/typescript/src/dy/api/SplashAd.d.ts.map +1 -1
  38. package/lib/typescript/src/dy/component/BannerAd.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/src/dy/api/AdManager.ts +42 -4
  41. package/src/dy/api/FullScreenVideo.ts +64 -2
  42. package/src/dy/api/RewardVideo.ts +63 -2
  43. package/src/dy/api/SplashAd.ts +75 -2
  44. package/src/dy/component/BannerAd.tsx +107 -5
package/README.md CHANGED
@@ -1,967 +1,328 @@
1
1
  # react-native-brayant-ad
2
2
 
3
- 接入穿山甲SDK
3
+ React Native 国内广告 SDK 封装,当前主要集成穿山甲(Pangle),支持以下能力:
4
+
5
+ - 开屏广告(支持预加载)
6
+ - 激励视频
7
+ - 全屏视频
8
+ - 信息流 Feed(组件)
9
+ - Draw 信息流(组件)
10
+ - Banner(组件)
11
+
12
+ ## 1. 安装
13
+
14
+ ```bash
15
+ pnpm add @24jieqi/react-native-brayant-ad
16
+ # 或
17
+ npm i @24jieqi/react-native-brayant-ad
18
+ # 或
19
+ yarn add @24jieqi/react-native-brayant-ad
20
+ ```
4
21
 
5
- ## 后期代办
22
+ ### iOS
6
23
 
7
- 接入GeoMoreSdk
24
+ 安装依赖后执行:
8
25
 
9
- ## 安装
26
+ ```bash
27
+ cd ios && pod install
28
+ ```
10
29
 
11
- ```sh
30
+ ## 2. 原生配置
12
31
 
13
- npm install @24jieqi/react-native-brayant-ad
14
- ```
32
+ ### 2.1 Android 仓库配置(必须)
15
33
 
16
- 在RN项目的 Project级别的 build.gradle 中添加如下配置 (android/build.gradle
34
+ 在宿主 App `android/build.gradle`(或你项目的统一仓库配置处)确保包含:
17
35
 
18
36
  ```groovy
19
37
  allprojects {
20
38
  repositories {
21
39
  google()
22
40
  mavenCentral()
23
- // 添加穿山甲SDK仓库
24
- maven {
25
- url 'https://artifact.bytedance.com/repository/pangle'
26
- }
41
+ maven { url 'https://artifact.bytedance.com/repository/pangle' }
27
42
  }
28
43
  }
29
44
  ```
30
45
 
31
- ### Android 完整集成配置
46
+ ### 2.2 iOS 隐私权限(建议)
32
47
 
33
- 由于本库底层使用穿山甲(Pangle)SDK,需要在 Android 项目中添加以下配置才能正常使用。
48
+ 如果你计划在 iOS 调用 `requestPermission()` 请求 ATT,请在 `Info.plist` 配置 `NSUserTrackingUsageDescription`。
34
49
 
35
- #### 添加 Pangle SDK 依赖
50
+ ## 3. 能力与平台支持
36
51
 
37
- 在你的 **android/build.gradle** `dependencies` 中添加:
52
+ | 能力 | 导出名 | Android | iOS |
53
+ | --- | --- | --- | --- |
54
+ | SDK 初始化 | `init` | ✅ | ✅ |
55
+ | ATT/权限请求 | `requestPermission` | ✅(Android 权限) | ✅(ATT) |
56
+ | 开屏广告 | `dyLoadSplashAd` | ✅ | ✅ |
57
+ | 开屏预加载 | `preloadSplashAd` / `hasPreloadedSplashAd` / `clearPreloadedSplashAd` | ✅ | ✅(兼容实现) |
58
+ | 激励视频 | `startRewardVideo` | ✅ | ✅ |
59
+ | 全屏视频 | `startFullScreenVideo` | ✅ | ✅ |
60
+ | Feed 信息流组件 | `FeedAdView` | ✅ | ✅ |
61
+ | Draw 信息流组件 | `DrawFeedView` / `loadDrawFeedAd` | ✅ | ❌ |
62
+ | Banner 组件 | `BannerAdView` | ✅ | ✅ |
38
63
 
39
- ```groovy
40
- dependencies {
41
- implementation 'com.pangle.cn:ads-sdk-pro:7.3.0.8'
42
- }
43
- ```
64
+ ## 4. 快速开始(推荐接入顺序)
44
65
 
45
- ## 必要配置
66
+ ### 4.1 初始化 SDK
46
67
 
47
- 在项目入口文件中初始化init, 如果不是全局初始化的就需要在每次调用的时候传入
68
+ 建议在 App 启动时调用一次:
48
69
 
49
- ```js
70
+ ```tsx
50
71
  import { init } from '@24jieqi/react-native-brayant-ad';
51
72
 
52
- useEffect(() => {
53
- init({
54
- appid: 'xxxx',
55
- app: 'app名称',
56
- amount: 1000,
57
- reward: '金币',
58
- debug: true,
59
- }).then((res) => {});
73
+ await init({
74
+ appid: '你的穿山甲 appid',
75
+ app: '你的应用名',
76
+ uid: '可选用户ID',
77
+ amount: 1000,
78
+ reward: '金币',
79
+ debug: false,
60
80
  });
61
81
  ```
62
82
 
63
- ### init 方法配置
64
-
65
- | 参数 | 说明 | 类型 | 默认值 | 是否必填 |
66
- | ------ | ------------------------------- | ------- | ------------- | -------- |
67
- | appid | 穿山甲中创建应用的appid | string | - | 是 |
68
- | app | app名称 | string | 穿山甲媒体APP | 否 |
69
- | uid | 有些uid和穿山甲商务有合作的需要 | string | - | 否 |
70
- | amount | 奖励数量 | number | 1000 | 否 |
71
- | reward | 奖励名称 | string | 金币 | 否 |
72
- | debug | 是否是开发者模式 | boolean | false | 否 |
73
-
74
- init 成功会返回一个promise
75
-
76
- # 1. 开屏广告
77
-
78
- ## API
79
-
80
- ### dyLoadSplashAd
81
-
82
- #### 开屏广告事件类型
83
-
84
- ```ts
85
- interface AD_EVENT_TYPE {
86
- onAdError: string; // 广告加载失败监听
87
- onAdClick: string; // 广告被点击监听
88
- onAdClose: string; // 广告关闭
89
- onAdSkip: string; // 用户点击跳过广告监听
90
- onAdShow: string; // 开屏广告开始展示
91
- }
92
-
93
- EmuAnim = 'default' | 'none' | 'catalyst' | 'slide' | 'fade';
94
- ```
95
-
96
- | 参数 | 说明 | 类型 | 默认值 | 是否必填 |
97
- | ------ | ------------ | ------- | ------- | -------- |
98
- | codeid | 广告位id | string | - | 是 |
99
- | anim | 广告进入方式 | EmuAnim | default | 否 |
100
-
101
- ### preloadSplashAd (Android 推荐)
102
-
103
- **Android 端推荐使用预加载方式,可避免启动页结束后出现白屏。**
104
-
105
- 在应用启动时(init 之后)预加载开屏广告,展示时直接使用已加载的广告。
106
-
107
- ```ts
108
- // 预加载开屏广告
109
- await preloadSplashAd({ codeid: 'your_code_id' });
110
-
111
- // 展示广告(使用预加载的广告,无白屏)
112
- const splashAd = dyLoadSplashAd({ codeid: 'your_code_id' });
113
- ```
114
-
115
- | 参数 | 说明 | 类型 | 默认值 | 是否必填 |
116
- | ------ | -------- | ------ | ------ | -------- |
117
- | codeid | 广告位id | string | - | 是 |
118
-
119
- ### hasPreloadedSplashAd
83
+ `init` 参数:
120
84
 
121
- 检查是否有预加载的广告可用(Android)。
122
-
123
- ```ts
124
- const { hasAd, status } = await hasPreloadedSplashAd();
125
- // hasAd: boolean - 是否有可用的预加载广告
126
- // status: number - 预加载状态 (0:未加载 1:加载中 2:成功 3:失败)
127
- ```
85
+ | 参数 | 类型 | 必填 | 说明 |
86
+ | --- | --- | --- | --- |
87
+ | `appid` | `string` | 是 | 穿山甲应用 ID |
88
+ | `app` | `string` | | 应用名 |
89
+ | `uid` | `string` | 否 | 业务侧用户标识 |
90
+ | `amount` | `number` | | 激励数量 |
91
+ | `reward` | `string` | 否 | 激励名称 |
92
+ | `debug` | `boolean` | 否 | 调试模式 |
128
93
 
129
- ### clearPreloadedSplashAd
94
+ ### 4.2 请求权限(按需)
130
95
 
131
- 清除预加载的广告缓存(Android)。
96
+ ```tsx
97
+ import { requestPermission } from '@24jieqi/react-native-brayant-ad';
132
98
 
133
- ```ts
134
- clearPreloadedSplashAd();
99
+ requestPermission();
135
100
  ```
136
101
 
137
- ## 如何使用
138
-
139
- ### 基础用法(实时加载)
140
-
141
- > 注意:这种方式在 Android 端可能会出现白屏
142
-
143
- ```tsx
144
- import { dyLoadSplashAd } from '@24jieqi/react-native-brayant-ad';
145
- import { Text, TouchableOpacity } from 'react-native';
146
-
147
- const ScrenPage = () => {
148
- const onOpenScren = () => {
149
- const splashAd = dyLoadSplashAd({
150
- codeid: '****',
151
- anim: 'default',
152
- });
153
-
154
- splashAd.subscribe('onAdClose', (event) => {
155
- console.log('广告关闭', event);
156
- });
157
-
158
- splashAd.subscribe('onAdSkip', (i) => {
159
- console.log('用户点击跳过监听', i);
160
- });
161
-
162
- splashAd.subscribe('onAdError', (e) => {
163
- console.log('开屏加载失败监听', e);
164
- });
165
-
166
- splashAd.subscribe('onAdClick', (e) => {
167
- console.log('开屏被用户点击了', e);
168
- });
169
-
170
- splashAd.subscribe('onAdShow', (e) => {
171
- console.log('开屏开始展示', e);
172
- });
173
- };
174
-
175
- return (
176
- <TouchableOpacity onPress={onOpenScren}>
177
- <Text style={{ textAlign: 'center' }}> 开屏</Text>
178
- </TouchableOpacity>
179
- );
180
- };
181
- ```
102
+ - Android:请求相关权限
103
+ - iOS:请求 ATT
182
104
 
183
- ### 推荐用法(预加载 - Android)
105
+ ## 5. 开屏广告
184
106
 
185
- **Android 端推荐使用预加载方式,避免启动页到广告之间出现白屏。**
107
+ ### 5.1 API
186
108
 
187
109
  ```tsx
188
110
  import {
189
- init,
111
+ dyLoadSplashAd,
190
112
  preloadSplashAd,
191
113
  hasPreloadedSplashAd,
192
- dyLoadSplashAd,
114
+ clearPreloadedSplashAd,
193
115
  } from '@24jieqi/react-native-brayant-ad';
194
- import { useEffect } from 'react';
195
-
196
- const App = () => {
197
- useEffect(() => {
198
- const initialize = async () => {
199
- // 1. 初始化 SDK
200
- await init({
201
- appid: 'your_app_id',
202
- app: '应用名称',
203
- debug: false,
204
- });
205
-
206
- // 2. Android: 预加载开屏广告(避免白屏)
207
- if (Platform.OS === 'android') {
208
- await preloadSplashAd({ codeid: 'your_splash_code_id' });
209
- console.log('开屏广告预加载完成');
210
- }
211
- };
212
-
213
- initialize();
214
- }, []);
215
-
216
- // 3. 展示开屏广告(Android使用预加载,iOS实时加载)
217
- const showSplash = async () => {
218
- // 检查预加载状态(可选)
219
- if (Platform.OS === 'android') {
220
- const { hasAd } = await hasPreloadedSplashAd();
221
- console.log('是否有预加载广告:', hasAd);
222
- }
223
-
224
- const splashAd = dyLoadSplashAd({
225
- codeid: 'your_splash_code_id',
226
- anim: 'default',
227
- });
228
-
229
- splashAd.subscribe('onAdShow', (event) => {
230
- console.log('广告展示', event);
231
- });
232
-
233
- splashAd.subscribe('onAdClose', (event) => {
234
- console.log('广告关闭', event);
235
- });
236
-
237
- splashAd.subscribe('onAdError', (error) => {
238
- console.log('广告错误', error);
239
- });
240
- };
241
-
242
- return (
243
- // ...
244
- );
245
- };
246
- ```
247
-
248
- ### 在应用启动时自动展示开屏广告
249
-
250
- ```tsx
251
- import { init, preloadSplashAd, dyLoadSplashAd } from '@24jieqi/react-native-brayant-ad';
252
- import { hide } from 'react-native-bootsplash';
253
-
254
- const SplashAdManager = () => {
255
- useEffect(() => {
256
- const showSplashAdOnLaunch = async () => {
257
- try {
258
- // 1. 初始化广告 SDK
259
- await init({ appid: 'your_app_id', app: '应用名称' });
260
-
261
- // 2. Android: 预加载广告
262
- if (Platform.OS === 'android') {
263
- await preloadSplashAd({ codeid: 'your_splash_code_id' });
264
- }
265
-
266
- // 3. 展示广告(Android使用预加载,无白屏)
267
- const splashAd = dyLoadSplashAd({
268
- codeid: 'your_splash_code_id',
269
- anim: 'fade',
270
- });
271
-
272
- splashAd.subscribe('onAdShow', () => {
273
- console.log('广告展示');
274
- // Android: 此时可以隐藏启动页(广告已准备好)
275
- hide({ fade: true });
276
- });
277
-
278
- splashAd.subscribe('onAdClose', () => {
279
- console.log('广告关闭');
280
- });
281
-
282
- splashAd.subscribe('onAdError', (error) => {
283
- console.log('广告加载失败', error);
284
- // 出错时也要隐藏启动页
285
- hide({ fade: true });
286
- });
287
- } catch (error) {
288
- console.error('广告初始化失败:', error);
289
- hide({ fade: true });
290
- }
291
- };
292
-
293
- showSplashAdOnLaunch();
294
- }, []);
295
-
296
- return null;
297
- };
298
116
  ```
299
117
 
300
- # 2. 激励视频
301
-
302
- ## API
118
+ `dyLoadSplashAd({ codeid, anim? })`
303
119
 
304
- ### requestPermission
120
+ - `codeid: string` 必填
121
+ - `anim?: 'default' | 'none' | 'catalyst' | 'slide' | 'fade'`
305
122
 
306
- > 主动看激励视频时,才检查这个权限
123
+ 返回对象:
307
124
 
308
- 无参数 `requestPermission()`
125
+ - `result`: Promise
126
+ - `subscribe(type, callback)`: 订阅事件
127
+ - `cleanup()`: 移除当前实例所有监听
309
128
 
310
- ### startRewardVideo 方法参数
129
+ 事件类型:
311
130
 
312
- > 开始看激励视频
131
+ - `onAdError`
132
+ - `onAdClick`
133
+ - `onAdClose`
134
+ - `onAdSkip`
135
+ - `onAdShow`
136
+ - `onPreloadSuccess`
137
+ - `onPreloadFail`
313
138
 
314
- ## API
139
+ ### 5.2 推荐:启动时预加载(尤其 Android)
315
140
 
316
- | 参数 | 说明 | 类型 | 默认值 | 是否必填 |
317
- | ------ | -------- | ------ | ------ | -------- |
318
- | codeid | 广告位id | string | - | 是 |
141
+ ```tsx
142
+ await preloadSplashAd({ codeid: '你的开屏广告位' });
319
143
 
320
- #### 激励视频事件类型
144
+ const { hasAd, status } = await hasPreloadedSplashAd();
145
+ // hasAd: 是否可直接展示
146
+ // status: 预加载状态码
321
147
 
322
- ```ts
323
- export enum AD_EVENT_TYPE {
324
- onAdError = 'onAdError', // 广告加载失败监听
325
- onAdLoaded = 'onAdLoaded', // 广告加载成功监听
326
- onAdClick = 'onAdClick', // 广告被点击监听
327
- onAdClose = 'onAdClose', // 广告关闭监听
148
+ if (hasAd) {
149
+ const splash = dyLoadSplashAd({ codeid: '你的开屏广告位' });
150
+ splash.subscribe('onAdClose', () => {});
328
151
  }
329
152
  ```
330
153
 
331
- ## 如何使用
332
-
333
- > 这边案列默认全部init初始化后
154
+ 不再使用时可清理缓存:
334
155
 
335
156
  ```tsx
336
- import {
337
- requestPermission,
338
- startRewardVideo,
339
- } from '@24jieqi/react-native-brayant-ad';
340
- import { Text, TouchableOpacity } from 'react-native';
341
-
342
- const RewardVideoPage = () => {
343
- const onStartRewardVideo = () => {
344
- const rewardVideo = startRewardVideo({
345
- codeid: '****',
346
- });
347
-
348
- rewardVideo.result.then((val: any) => {
349
- console.log('RewardVideo 回调结果', val);
350
- });
351
-
352
- rewardVideo.subscribe('onAdLoaded', (event) => {
353
- console.log('广告加载成功监听', event);
354
- });
355
-
356
- rewardVideo.subscribe('onAdError', (event) => {
357
- console.log('广告加载失败监听', event);
358
- });
359
-
360
- rewardVideo.subscribe('onAdClose', (event) => {
361
- console.log('广告被关闭监听', event);
362
- });
363
-
364
- rewardVideo.subscribe('onAdClick', (event) => {
365
- console.log('广告点击查看详情监听', event);
366
- });
367
- };
368
-
369
- return (
370
- <TouchableOpacity onPress={onStartRewardVideo}>
371
- <Text style={{ textAlign: 'center' }}> 激励视频</Text>
372
- </TouchableOpacity>
373
- );
374
- };
157
+ clearPreloadedSplashAd();
375
158
  ```
376
159
 
377
- # 3. 全屏视频广告
378
-
379
- ## api
380
-
381
- ### startFullScreenVideo 方法参数
382
-
383
- | 参数 | 说明 | 类型 | 默认值 | 是否必填 |
384
- | ----------- | -------- | -------------------------- | -------- | -------- | --- | --- |
385
- | codeid | 广告位id | string | - | 是 |
386
- | orientation | 竖屏横屏 | 'HORIZONTAL' \| 'VERTICAL' | VERTICAL | 否 | - | 是 |
387
-
388
- ## 使用
160
+ ## 6. 激励视频
389
161
 
390
162
  ```tsx
391
- import {
392
- requestPermission,
393
- startFullScreenVideo,
394
- } from '@24jieqi/react-native-brayant-ad';
395
- import { useEffect } from 'react';
396
- import { Text, TouchableOpacity } from 'react-native';
397
-
398
- const RewardVideoPage = () => {
399
- useEffect(() => {
400
- // step 1: 获取权限
401
- requestPermission();
402
- }, []);
403
-
404
- return (
405
- <TouchableOpacity
406
- style={{
407
- marginVertical: 20,
408
- paddingHorizontal: 30,
409
- paddingVertical: 15,
410
- backgroundColor: '#F96',
411
- borderRadius: 50,
412
- }}
413
- onPress={() => {
414
- let fullVideo = startFullScreenVideo({
415
- codeid: '****',
416
- });
417
- console.log('FullVideoAd rs:', fullVideo);
418
- fullVideo.result?.then((val: any) => {
419
- console.log('FullVideoAd rs then val', val);
420
- });
421
-
422
- fullVideo.subscribe('onAdLoaded' as any, (event) => {
423
- console.log('广告加载成功监听', event);
424
- });
425
-
426
- fullVideo.subscribe('onAdError' as any, (event) => {
427
- console.log('广告加载失败监听', event);
428
- });
429
-
430
- fullVideo.subscribe('onAdClose' as any, (event) => {
431
- console.log('广告被关闭监听', event);
432
- });
433
-
434
- fullVideo.subscribe('onAdClick' as any, (event) => {
435
- console.log('广告点击查看详情监听', event);
436
- });
437
- }}
438
- >
439
- <Text style={{ textAlign: 'center' }}> Start 全屏视频广告</Text>
440
- </TouchableOpacity>
441
- );
442
- };
443
- ```
444
-
445
- # 4. Draw广告
446
-
447
- ## api
448
-
449
- ### loadDrawFeedAd 方法参数
450
-
451
- | 参数 | 说明 | 类型 | 默认值 | 是否必填 |
452
- | ------ | -------- | ------ | ------ | -------- | --- | --- |
453
- | codeid | 广告位id | string | - | 是 |
454
- | appid | 应用id | string | - | 是 | - | 是 |
455
-
456
- ## 组件
163
+ import { startRewardVideo } from '@24jieqi/react-native-brayant-ad';
457
164
 
458
- ### DrawFeedView
165
+ const reward = startRewardVideo({ codeid: '你的激励广告位' });
459
166
 
460
- | 参数 | 说明 | 类型 | 默认值 | 是否必填 |
461
- | --------- | ------------------ | --------- | ------ | -------- |
462
- | codeid | 广告位id | string | - | 是 |
463
- | appid | 应用id | string | - | 是 |
464
- | visible | 是否显示组件中广告 | boolean | - | 否 |
465
- | appid | 应用id | string | - | 是 |
466
- | style | 组件样式 | ViewStyle | - | 否 |
467
- | onAdError | 广告错误事件 | Function | - | 否 |
468
- | onAdShow | 显示广告事件 | Function | - | 否 |
469
- | onAdClick | 点击广告事件 | Function | - | 否 |
167
+ reward.result.then((res) => {
168
+ console.log('激励视频结果', res);
169
+ });
470
170
 
471
- ## 使用
171
+ reward.subscribe('onAdLoaded', (e) => console.log('加载成功', e));
172
+ reward.subscribe('onAdError', (e) => console.log('加载失败', e));
173
+ reward.subscribe('onAdClick', (e) => console.log('点击', e));
174
+ reward.subscribe('onAdClose', (e) => console.log('关闭', e));
472
175
 
473
- ```tsx
474
- import { loadDrawFeedAd, DrawFeedView } from '@24jieqi/react-native-brayant-ad';
475
- import { useEffect } from 'react';
476
-
477
- const RewardVideoPage = () => {
478
- useEffect(() => {
479
- loadDrawFeedAd({
480
- appid: '****',
481
- codeid: '****',
482
- });
483
- }, []);
484
-
485
- return (
486
- <DrawFeedView
487
- codeid={'****'}
488
- appid={'****'}
489
- visible={true}
490
- onAdError={(e: any) => {
491
- console.log('DrawFeedAd 加载失败', e);
492
- }}
493
- onAdShow={(e: any) => {
494
- console.log('DrawFeedAd 开屏开始展示', e);
495
- }}
496
- onAdClick={(e: any) => {
497
- console.log('onAdClick DrawFeed', e.nativeEvent);
498
- }}
499
- />
500
- );
501
- };
176
+ // 页面销毁时
177
+ reward.cleanup();
502
178
  ```
503
179
 
504
- # 5. Banner广告
180
+ 支持事件:`onAdError`、`onAdLoaded`、`onAdClick`、`onAdClose`。
505
181
 
506
- > 注意:Banner广告目前仅支持Android平台
182
+ ## 7. 全屏视频
507
183
 
508
- ## API
509
-
510
- ### preloadBannerAd
184
+ ```tsx
185
+ import { startFullScreenVideo } from '@24jieqi/react-native-brayant-ad';
511
186
 
512
- 预加载 Banner 广告(Android 专用)
187
+ const full = startFullScreenVideo({
188
+ codeid: '你的全屏广告位',
189
+ orientation: 'VERTICAL', // 可选:HORIZONTAL | VERTICAL
190
+ provider: '头条', // 可选:头条 | 腾讯 | 快手(主要 Android 使用)
191
+ });
513
192
 
514
- 在组件渲染前调用,提前加载广告数据,减少白屏时间。预加载的广告会缓存 5 分钟,过期后自动失效。
193
+ full.result.then((res) => {
194
+ console.log('全屏视频结果', res);
195
+ });
515
196
 
516
- | 参数 | 说明 | 类型 | 默认值 | 是否必填 |
517
- | -------- | ------------ | ------ | ------ | -------- |
518
- | codeid | 广告位 ID | string | - | 是 |
519
- | adWidth | 广告宽度(dp) | number | 320 | 否 |
520
- | adHeight | 广告高度(dp) | number | 50 | 否 |
197
+ full.subscribe('onAdLoaded', () => {});
198
+ full.subscribe('onAdError', () => {});
199
+ full.subscribe('onAdClick', () => {});
200
+ full.subscribe('onAdClose', () => {});
521
201
 
522
- ```tsx
523
- import { NativeModules } from 'react-native';
524
- const { BannerAdModule } = NativeModules;
525
-
526
- // 在页面进入前预加载
527
- useEffect(() => {
528
- BannerAdModule.preloadBannerAd({
529
- codeid: 'your_codeid',
530
- adWidth: 320,
531
- adHeight: 50,
532
- });
533
- }, []);
202
+ // 页面销毁时
203
+ full.cleanup();
534
204
  ```
535
205
 
536
- ### hasPreloadedBannerAd
537
-
538
- 检查是否有预加载的 Banner 广告
206
+ ## 8. Feed 信息流组件
539
207
 
540
208
  ```tsx
541
- const hasCache = await BannerAdModule.hasPreloadedBannerAd('your_codeid');
542
- ```
543
-
544
- ### clearPreloadedBannerAd
209
+ import { FeedAdView, preloadFeedAd } from '@24jieqi/react-native-brayant-ad';
545
210
 
546
- 清除预加载的 Banner 广告缓存
211
+ await preloadFeedAd({ codeid: '你的Feed广告位', adWidth: 375 });
547
212
 
548
- ```tsx
549
- BannerAdModule.clearPreloadedBannerAd();
213
+ <FeedAdView
214
+ codeid="你的Feed广告位"
215
+ adWidth={375}
216
+ visible={true}
217
+ onAdLayout={(e) => console.log('渲染成功', e)}
218
+ onAdError={(e) => console.log('加载失败', e)}
219
+ onAdClick={(e) => console.log('点击', e)}
220
+ onAdClose={(e) => console.log('关闭', e)}
221
+ />
550
222
  ```
551
223
 
552
- ## 组件
224
+ `FeedAdView` 主要参数:
553
225
 
554
- ### BannerAdView
226
+ - `codeid: string`(必填)
227
+ - `adWidth?: number`
228
+ - `visible?: boolean`
229
+ - `style?: ViewStyle`
230
+ - `onAdLayout/onAdError/onAdClick/onAdClose`
555
231
 
556
- | 参数 | 说明 | 类型 | 默认值 | 是否必填 |
557
- | ----------------- | ------------------ | --------- | ------ | -------- |
558
- | codeid | 广告位id | string | - | 是 |
559
- | adWidth | 广告宽度(dp) | number | 320 | 否 |
560
- | adHeight | 广告高度(dp) | number | 50 | 否 |
561
- | visible | 是否显示组件中广告 | boolean | - | 否 |
562
- | style | 组件样式 | ViewStyle | - | 否 |
563
- | onAdRenderSuccess | 广告渲染成功事件 | Function | - | 否 |
564
- | onAdError | 广告加载失败事件 | Function | - | 否 |
565
- | onAdDismiss | 广告关闭事件 | Function | - | 否 |
566
- | onAdClick | 广告被用户点击事件 | Function | - | 否 |
567
- | onAdShow | 广告展示事件 | Function | - | 否 |
568
- | onAdDislike | 用户不感兴趣事件 | Function | - | 否 |
232
+ ## 9. Draw 信息流组件(Android)
569
233
 
570
- ## 使用
234
+ ```tsx
235
+ import { DrawFeedView, loadDrawFeedAd } from '@24jieqi/react-native-brayant-ad';
571
236
 
572
- ### 基础用法
237
+ loadDrawFeedAd({
238
+ appid: '你的 appid',
239
+ codeid: '你的 Draw 广告位',
240
+ });
573
241
 
574
- ```tsx
575
- import { BannerAdView, init } from '@24jieqi/react-native-brayant-ad';
576
- import { useEffect, useState } from 'react';
577
- import { View } from 'react-native';
578
-
579
- const BannerAdPage = () => {
580
- const [showBannerView, setShowBannerView] = useState(false);
581
-
582
- useEffect(() => {
583
- init({
584
- appid: '****',
585
- app: '设备信息',
586
- }).then((res) => {
587
- setShowBannerView(true);
588
- });
589
- }, []);
590
-
591
- return (
592
- <View>
593
- <BannerAdView
594
- codeid={'****'}
595
- adWidth={320}
596
- adHeight={50}
597
- visible={showBannerView}
598
- onAdRenderSuccess={(data: any) => {
599
- console.log('Banner 广告渲染成功!', data);
600
- }}
601
- onAdError={(err: any) => {
602
- console.log('Banner 广告加载失败!', err);
603
- }}
604
- onAdDismiss={(data: any) => {
605
- console.log('Banner 广告关闭!', data);
606
- }}
607
- onAdClick={(val: any) => {
608
- console.log('Banner 广告被用户点击!', val);
609
- }}
610
- onAdShow={(val: any) => {
611
- console.log('Banner 广告展示', val);
612
- }}
613
- onAdDislike={(val: any) => {
614
- console.log('Banner 用户不感兴趣', val);
615
- }}
616
- />
617
- </View>
618
- );
619
- };
242
+ <DrawFeedView
243
+ appid="你的 appid"
244
+ codeid="你的 Draw 广告位"
245
+ visible={true}
246
+ onAdShow={(e) => console.log('展示', e)}
247
+ onAdClick={(e) => console.log('点击', e)}
248
+ onAdError={(e) => console.log('错误', e)}
249
+ />
620
250
  ```
621
251
 
622
- ### 推荐用法(预加载)
252
+ ## 10. Banner 组件(Android / iOS)
623
253
 
624
254
  ```tsx
625
255
  import { BannerAdView } from '@24jieqi/react-native-brayant-ad';
626
- import { NativeModules } from 'react-native';
627
- import { useEffect, useState } from 'react';
628
- import { View } from 'react-native';
629
-
630
- const { BannerAdModule } = NativeModules;
631
-
632
- const BannerAdPage = () => {
633
- const [showBannerView, setShowBannerView] = useState(false);
634
-
635
- useEffect(() => {
636
- // 先预加载广告,再显示组件
637
- const preloadAndShow = async () => {
638
- try {
639
- await BannerAdModule.preloadBannerAd({
640
- codeid: 'your_codeid',
641
- adWidth: 320,
642
- adHeight: 50,
643
- });
644
- } catch (error) {
645
- console.log('预加载失败', error);
646
- } finally {
647
- // 无论预加载成功与否,都显示组件
648
- setShowBannerView(true);
649
- }
650
- };
651
-
652
- preloadAndShow();
653
- }, []);
654
-
655
- return (
656
- <View>
657
- <BannerAdView
658
- codeid={'your_codeid'}
659
- adWidth={320}
660
- adHeight={50}
661
- visible={showBannerView}
662
- onAdRenderSuccess={(data: any) => {
663
- console.log('Banner 广告渲染成功!', data);
664
- }}
665
- onAdError={(err: any) => {
666
- console.log('Banner 广告加载失败!', err);
667
- }}
668
- />
669
- </View>
670
- );
671
- };
672
- ```
673
-
674
- # 6. 信息流广告
675
-
676
- ## API
677
-
678
- ### preloadFeedAd
679
-
680
- 预加载信息流广告(Android 专用)
681
-
682
- 在组件渲染前调用,提前加载广告数据,减少白屏时间。
683
256
 
684
- | 参数 | 说明 | 类型 | 默认值 | 是否必填 |
685
- | ------- | ------------ | ------ | ------ | -------- |
686
- | appid | 应用 ID | string | - | 是 |
687
- | codeid | 广告位 ID | string | - | 是 |
688
- | adWidth | 广告宽度(dp) | string | '280' | 否 |
689
-
690
- ```tsx
691
- import { preloadFeedAd } from '@24jieqi/react-native-brayant-ad';
692
-
693
- // 在页面进入前预加载
694
- useEffect(() => {
695
- preloadFeedAd({
696
- appid: 'your_appid',
697
- codeid: 'your_codeid',
698
- adWidth: '375',
699
- });
700
- }, []);
257
+ <BannerAdView
258
+ codeid="你的 Banner 广告位"
259
+ adWidth={320}
260
+ adHeight={50}
261
+ visible={true}
262
+ onAdRenderSuccess={(e) => console.log('渲染成功', e)}
263
+ onAdError={(e) => console.log('加载失败', e)}
264
+ onAdShow={(e) => console.log('展示', e)}
265
+ onAdClick={(e) => console.log('点击', e)}
266
+ onAdDismiss={(e) => console.log('关闭', e)}
267
+ onAdDislike={(e) => console.log('不感兴趣', e)}
268
+ />
701
269
  ```
702
270
 
703
- ## 组件
704
-
705
- ### FeedAdView
271
+ 说明:
706
272
 
707
- | 参数 | 说明 | 类型 | 默认值 | 是否必填 |
708
- | ---------- | ------------------ | --------- | ------ | -------- |
709
- | codeid | 广告位id | string | - | 是 |
710
- | adWidth | 广告宽度 | number | 375 | 否 |
711
- | visible | 是否显示组件中广告 | boolean | - | 否 |
712
- | style | 组件样式 | ViewStyle | - | 否 |
713
- | onAdLayout | 广告加载成功事件 | Function | - | 否 |
714
- | onAdClose | 广告关闭事件 | Function | - | 否 |
715
- | onAdClick | 广告被用户点击事件 | Function | - | 否 |
716
- | onAdError | 广告加载失败事件 | Function | - | 否 |
273
+ - Android / iOS 均可使用同一套 `BannerAdView` 参数。
274
+ - iOS 端不触发 `onAdDislike`(该事件主要用于 Android)。
717
275
 
718
- ## 使用
276
+ ## 11. 导出清单
719
277
 
720
- ### 基础用法
721
-
722
- ```tsx
723
- import { FeedAdView } from '@24jieqi/react-native-brayant-ad';
724
- import { useEffect, useState } from 'react';
725
-
726
- const RewardVideoPage = () => {
727
- const [showFeedView, setShowFeedView] = useState(false);
728
-
729
- useEffect(() => {
730
- setShowFeedView(true);
731
- }, []);
732
-
733
- return (
734
- <FeedAdView
735
- codeid={'****'}
736
- adWidth={400}
737
- visible={showFeedView}
738
- onAdLayout={(data: any) => {
739
- console.log('Feed 广告加载成功!', data);
740
- }}
741
- onAdClose={(data: any) => {
742
- console.log('Feed 广告关闭!', data);
743
- }}
744
- onAdError={(err: any) => {
745
- console.log('Feed 广告加载失败!', err);
746
- }}
747
- onAdClick={(val: any) => {
748
- console.log('Feed 广告被用户点击!', val);
749
- }}
750
- />
751
- );
752
- };
278
+ ```ts
279
+ import {
280
+ init,
281
+ requestPermission,
282
+ loadFeedAd,
283
+ preloadFeedAd,
284
+ dyLoadSplashAd,
285
+ preloadSplashAd,
286
+ hasPreloadedSplashAd,
287
+ clearPreloadedSplashAd,
288
+ startRewardVideo,
289
+ startFullScreenVideo,
290
+ loadDrawFeedAd,
291
+ DrawFeedView,
292
+ FeedAdView,
293
+ BannerAdView,
294
+ } from '@24jieqi/react-native-brayant-ad';
753
295
  ```
754
296
 
755
- ### 推荐用法(预加载)
297
+ ## 12. 常见问题
756
298
 
757
- ```tsx
758
- import { FeedAdView, preloadFeedAd } from '@24jieqi/react-native-brayant-ad';
759
- import { useEffect, useState } from 'react';
760
-
761
- const RewardVideoPage = () => {
762
- const [showFeedView, setShowFeedView] = useState(false);
763
-
764
- // 页面进入时预加载广告
765
- useEffect(() => {
766
- preloadFeedAd({
767
- appid: 'your_appid',
768
- codeid: 'your_codeid',
769
- }).then(() => {
770
- // 预加载成功后显示组件
771
- setShowFeedView(true);
772
- });
773
- }, []);
774
-
775
- return (
776
- <FeedAdView
777
- codeid={'your_codeid'}
778
- adWidth={375}
779
- visible={showFeedView}
780
- onAdLayout={(data: any) => {
781
- console.log('Feed 广告加载成功!', data);
782
- }}
783
- onAdError={(err: any) => {
784
- console.log('Feed 广告加载失败!', err);
785
- }}
786
- />
787
- );
788
- };
789
- ```
299
+ ### 12.1 提示模块未链接(`doesn't seem to be linked`)
790
300
 
791
- ### 在列表中使用不同广告位 ID
301
+ - 确认已重新编译 App(不是仅热更新)
302
+ - iOS 确认执行过 `pod install`
303
+ - 确认不是在 Expo Go 中运行
792
304
 
793
- 当需要在列表中展示不同位置的广告时,可以通过传入不同的 `adId` 来实现(组件内部会根据 `adId` 自动映射到对应的广告位):
305
+ ### 12.2 Android 开屏后出现白屏
794
306
 
795
- ```tsx
796
- import { FeedAdView } from '@24jieqi/react-native-brayant-ad';
797
- import { FlatList, View, Text } from 'react-native';
798
-
799
- // 定义广告位池配置(可选,用于实现广告位轮询)
800
- const AD_SLOT_POOL = [
801
- 'your_codeid_1', // 第5位广告
802
- 'your_codeid_2', // 第10位广告
803
- ];
804
-
805
- // 根据 adId 选择广告位(实现轮询逻辑)
806
- const getSlotIdByAdId = (adId: string): string => {
807
- const index = adId
808
- .split('')
809
- .reduce((acc, char) => acc + char.charCodeAt(0), 0);
810
- return AD_SLOT_POOL[index % AD_SLOT_POOL.length];
811
- };
812
-
813
- const ListPage = () => {
814
- const renderItem = ({ item, index }: { item: any; index: number }) => {
815
- // 在第5位和第10位插入广告
816
- if (index === 5 || index === 10) {
817
- // 生成唯一的 adId,例如:ad_5_1707123456789
818
- const adId = `ad_${index}_${Date.now()}`;
819
-
820
- return (
821
- <>
822
- {/* 正常列表项 */}
823
- <View style={{ padding: 16 }}>
824
- <Text>{item.title}</Text>
825
- </View>
826
- {/* 广告组件 - 使用 adId 作为唯一标识 */}
827
- <FeedAdView
828
- key={adId} // 强制重新创建组件实例
829
- codeid={getSlotIdByAdId(adId)}
830
- adWidth={375}
831
- visible={true}
832
- onAdLayout={(data: any) => {
833
- console.log(`位置 ${index} 广告加载成功!`, data);
834
- }}
835
- onAdError={(err: any) => {
836
- console.log(`位置 ${index} 广告加载失败!`, err);
837
- }}
838
- />
839
- </>
840
- );
841
- }
842
-
843
- return (
844
- <View style={{ padding: 16 }}>
845
- <Text>{item.title}</Text>
846
- </View>
847
- );
848
- };
849
-
850
- return (
851
- <FlatList
852
- data={listData}
853
- renderItem={renderItem}
854
- keyExtractor={(item, index) => `item-${index}`}
855
- />
856
- );
857
- };
858
- ```
307
+ 优先使用 `preloadSplashAd` 在启动后预加载,再用 `dyLoadSplashAd` 展示。
859
308
 
860
- #### 封装 NativeAd 组件(推荐用法)
309
+ ### 12.3 监听器重复触发
861
310
 
862
- 为了更好的开发体验,建议封装一个 `NativeAd` 组件,对外暴露 `adId` 参数:
311
+ 每次创建广告实例后,在页面卸载时调用 `cleanup()`,并避免同一实例重复绑定同一事件。
863
312
 
864
- ```tsx
865
- import { FeedAdView, preloadFeedAd } from '@24jieqi/react-native-brayant-ad';
866
- import React, { useEffect, useState } from 'react';
867
- import { View } from 'react-native';
868
-
869
- interface NativeAdProps {
870
- adId: string; // 唯一广告标识,用于瀑布流场景
871
- slotID?: string; // 可选:指定广告位,不传则使用默认或轮询
872
- style?: ViewStyle;
873
- onAdLoaded?: Function;
874
- onAdError?: Function;
875
- onAdClick?: Function;
876
- onAdClose?: Function;
877
- }
313
+ ## 13. 本地开发
878
314
 
879
- // 广告位池配置
880
- const AD_SLOT_POOL = [
881
- 'your_codeid_for_position_5',
882
- 'your_codeid_for_position_10',
883
- ];
884
-
885
- // 根据 adId 选择广告位(实现轮询)
886
- const getSlotIdByAdId = (adId: string): string => {
887
- const index = adId
888
- .split('')
889
- .reduce((acc, char) => acc + char.charCodeAt(0), 0);
890
- return AD_SLOT_POOL[index % AD_SLOT_POOL.length];
891
- };
892
-
893
- export const NativeAd: React.FC<NativeAdProps> = ({
894
- adId,
895
- slotID,
896
- style,
897
- onAdLoaded,
898
- onAdError,
899
- onAdClick,
900
- onAdClose,
901
- }) => {
902
- const [isReady, setIsReady] = useState(false);
903
- const codeid = slotID || getSlotIdByAdId(adId);
904
-
905
- useEffect(() => {
906
- // 预加载广告
907
- preloadFeedAd({ appid: 'your_appid', codeid })
908
- .then(() => setIsReady(true))
909
- .catch(() => setIsReady(true));
910
- }, [codeid]);
911
-
912
- if (!isReady) return null;
913
-
914
- return (
915
- <View style={style}>
916
- <FeedAdView
917
- key={adId} // 关键:强制重新创建组件实例
918
- codeid={codeid}
919
- adWidth={375}
920
- visible={true}
921
- onAdLayout={(e) => onAdLoaded?.(e.nativeEvent)}
922
- onAdError={(e) => onAdError?.(e.nativeEvent)}
923
- onAdClick={(e) => onAdClick?.(e.nativeEvent)}
924
- onAdClose={(e) => onAdClose?.(e.nativeEvent)}
925
- />
926
- </View>
927
- );
928
- };
929
-
930
- export default NativeAd;
315
+ ```bash
316
+ pnpm typecheck
317
+ pnpm lint
318
+ pnpm test
319
+ pnpm prepare
931
320
  ```
932
321
 
933
- **使用封装的组件**:
322
+ 如果你修改了库源码(`src/`),请先执行:
934
323
 
935
- ```tsx
936
- import { NativeAd } from './NativeAd';
937
-
938
- // 在列表中使用 - 只需传入 adId
939
- <FlatList
940
- data={data}
941
- renderItem={({ item, index }) => (
942
- <View>
943
- <Text>{item.title}</Text>
944
- {/* 第5位和第10位插入不同广告 */}
945
- {index === 5 && <NativeAd adId="ad_5_1707123456789" />}
946
- {index === 10 && <NativeAd adId="ad_10_1707123456790" />}
947
- </View>
948
- )}
949
- />
324
+ ```bash
325
+ pnpm prepare
950
326
  ```
951
327
 
952
- **关键点说明**:
953
-
954
- | 参数 | 说明 | 示例 |
955
- |------|------|------|
956
- | `adId` | 唯一广告标识,用于区分不同位置的广告 | `ad_5_1707123456789` |
957
- | `key={adId}` | 强制 React 重新创建组件实例,确保每次展示不同广告 | - |
958
- | `getSlotIdByAdId` | 根据 `adId` 哈希计算选择广告位,实现轮询 | - |
959
- | `slotID` | 可选参数,直接指定广告位 ID | `your_codeid_1` |
960
-
961
- ## License
962
-
963
- MIT
964
-
965
- ---
966
-
967
- Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
328
+ 然后再运行示例工程。