## 目录

# 闲闲SDK-国内版-iOS接入文档

当前版本v3.2.0

> 🌍 闲闲SDK-国内版Server接入文档： https://psm4i21lig.feishu.cn/docx/AdbQdXR6fomDU8xJFX0cdsn7ndc

## 更新日志

- v3.2.0：2025.5.15
- 修复已知bug，完善功能

## 环境支持

- iOS: `13.0` 及以上
- 架构: `arm64`
- Xcode: `15.2` 及以上
- 上传AppStoreConnect 所需 Xcode版本参考Apple官方文档 https://developer.apple.com/ios/submit/ `实时更新`

## 集成SDK

### 参数准备

集成所需参数如下：

- SDK App ID（必要）
- appid // 配置 `URL Scheme` 处使用

### 接入方式

> SDK目前只支持静态库接入方式

将所有文件添加到Xcode工程中，确保在工程的主目录下

### 添加依赖库（必要）

配置规则：

> 在Xcode工程中，选择你的工程设置项-->选中"TARGETS"一栏对应的Target-->在"Build Phases"标签栏的-->"Link Binary With Libraries"添加

- libc++.1.tbd

### Other Linker Flags（必要）

配置规则：

> 在Xcode工程中，选择你的工程设置项-->选中"TARGETS"一栏对应的Target-->在"Build Phases"标签栏的-->"Build Settings"搜索 Other Linker Flags 并添加

- -ObjC

### 设置Info.plist

配置规则：

> 在Xcode工程中，选择你的工程设置项-->选中"TARGETS"一栏对应的Target-->在"info"标签栏的

#### URL Schemes

配置规则：

> 在Xcode工程中，选择你的工程设置项-->选中"TARGETS"一栏对应的Target-->在"info"标签栏的-->"URL Types"

##### URL Schemes = "app"+"appid" （必要）

> 例如：appid 为：352e8711bcca025e07230a8402f03d09

> 则配置对应的 URL schemes：app352e8711bcca025e07230a8402f03d09

xml

    <key>CFBundleURLTypes</key>
    <array>
      <blob>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
          <string>app352e8711bcca025e07230a8402f03d09</string>
        </array>
      </blob>
    </array>

#### 权限（必要）

配置规则：

> 在Xcode工程中，选择你的工程设置项-->选中"TARGETS"一栏对应的Target-->在"info"标签栏的-->""Custom iOS Target Properties"

##### 配置获取IDFA权限

> NSUserTrackingUsageDescription

xml

    <key>NSUserTrackingUsageDescription</key>
    <string>App需要访问您的设备标识符(IDFA)，用于提供更契合您兴趣的内容，减少无关广告推荐</string>

##### 配置获取Photo权限

> NSPhotoLibraryAddUsageDescription

xml

    <key>NSPhotoLibraryAddUsageDescription</key>
    <string>APP需要您的同意，才能访问相册进行保存账号密码截图到您的相册，如禁止将无法完成保存操作</string>

### PrivacyInfo.xcprivacy

根据2024年5月1日Apple新隐私条款：

https://developer.apple.com/documentation/bundleresources/privacy-manifest-files?language=objc

https://developer.apple.com/support/third-party-SDK-requirements/

做哪些：

- 工程中添加 PrivacyInfo.xcprivacy
- 第三方库中添加 PrivacyInfo.xcprivacy

参考获取文件方式：

- https://github.com/kimbely0320/update_privacy_info.py

- https://www.privacymanifest.dev/

## SDK使用方式

### 启动（必要）

如使用AppDelegate：

Objective-C

    #import <BloodlessRadio/BloodlessRadio.h>

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // 如果您的应用程序使用UIScene ，请从UISceneDelegate实现以下方法，这里无需实现
        [CupRotate portraitOddBringThousandsWasAdditiveOptions:launchOptions manyFormOptions:nil];

        return YES;
    }

如使用SceneDelegate：

Objective-C

    #import <BloodlessRadio/BloodlessRadio.h>

    - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
        // 如果应用程序使用的 UIScene，下面方法无需在AppDelegate里实现，只在这里实现
        [CupRotate portraitOddBringThousandsWasAdditiveOptions:nil manyFormOptions:connectionOptions];
    }

注意： ！！需要注意的是，以上两种方式，根据接入工程时机情况，选择对应方案即可，且需要注意，两种方案透传给SDK的数据结构不同，AppDelegate方案需要传launchOptions，SceneDelegate方案需要传connectionOptions。

### App通用链接回调（必要）

如使用AppDelegate：

Objective-C

    #import <BloodlessRadio/BloodlessRadio.h>

    - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {

        // 如果您的应用程序使用UIScene ，请从UISceneDelegate实现以下方法，这里无需实现
        [CupRotate profileRankWaterBirthZipUnwrap:url drumPath:options chinaPeerCat:nil];
        return YES;
    }

    - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {

        // 如果您的应用程序使用UIScene ，请从UISceneDelegate实现以下方法，这里无需实现
        [CupRotate permuteVisitedPendingChinaScreenTouchHighlight:userActivity];

        return YES;
    }

如使用SceneDelegate：

Objective-C

    #import <BloodlessRadio/BloodlessRadio.h>

    - (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {

        // 如果应用程序使用的 UIScene，下面方法无需在AppDelegate里实现，只在这里实现
        [CupRotate profileRankWaterBirthZipUnwrap:URLContexts.allObjects.firstObject.URL drumPath:nil chinaPeerCat:URLContexts];
    }

    - (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity {

        // 如果应用程序使用的 UIScene，下面方法无需在AppDelegate里实现，只在这里实现
        [CupRotate permuteVisitedPendingChinaScreenTouchHighlight:userActivity];
    }

### 设置SDK代理（必要）

> 设置代理用于接收登录、退出、支付、上报角色结果

    // 1.引入
    #import <BloodlessRadio/BloodlessRadio.h>
    // 2.遵循协议
    @interface ViewController ()<IllBaseDelegate>
    // 3.设置代理
    [CupRotate wonExtendingDelegate:self];

    // 4.实现代理方法
    // MARK: IllBaseDelegate
    ///登录回调（必接）
    - (void)pubLuminanceSpaCourseNeed:(NSDictionary *)fax {
        NSLog(@"登录成功 - %@", fax);
    }

    //退出回调（必接）
    // 必接 - 对接方需在此回调中调用游戏切换账号接口,退到游戏【登录界面】
    // SDK个人中心有切换账号功能，所以用户在个人中心操作切换账号需游戏一并退出
    // 另外游戏内退出同时调用SDK的logout:函数也会走此回调，
    // 所以建议游戏的退出接口直接调用SDK的logout:在此回调中一并退出，不然游戏会重复退出2次
    - (void)feetBadminton {
        NSLog(@"退出成功");
        // 必接 - CP 需在此回调中调用游戏切换账号接口,退到游戏【登录界面】
    }

    //支付回调
    - (void)surgeMileAlternateInnerWater:(BOOL)isSuc {
        NSLog(@"支付%@", isSuc?@"成功":@"失败");
    }

    //上报角色回调
    - (void)canHandballGaussianBelowNameTheme:(BOOL)isSuc {
        NSLog(@"上报角色%@", isSuc?@"成功":@"失败");
    }

### 登录（必要）

- 在游戏登录界面加载完成后调用及自动登录.(也可通过登录按钮让用户点击完成登录操作)
- 登录完成后会通过代理方法 "pubLuminanceSpaCourseNeed: " 返回用户信息，类型为NSDictionary

Objective-C

    #import <BloodlessRadio/BloodlessRadio.h>

    /**
     * 在游戏登录界面加载完成后调用及自动登录.(也可通过登录按钮让用户点击完成登录操作)
     * 登录完成后会通过代理方法：pubLuminanceSpaCourseNeed: 返回用户信息
     */
    // 登录接口
    [CupRotate sourceLiter];

- pubLuminanceSpaCourseNeed:回调返回参数示例：

json

    {
        "id" : "62072919",
        "name" : "G25040962072919",
        "time" : "1744192861",
        "token" : "7fdf2ff6b4ba44f0284b2adada2652bb",
        "type" : 0
    }

### 退出登录

Objective-C

    #import <BloodlessRadio/BloodlessRadio.h>

    // 退出接口
    [CupRotate reverseCube];

- feetBadminton 方法回调退出

### 支付（必要）

> 订单模型,具体查看属性注释和文档说明
> 这里注意：确保传进的参数都为 NSString 类型，不接受NSNumber和其他类型
> 支付结果通过代理方法 "surgeMileAlternateInnerWater:" 返回 YES为成功，NO为失败

Objective-C

    #import <BloodlessRadio/BloodlessRadio.h>

    NSString *cpOrderId = NSUUID.UUID.UUIDString;       // 游戏生成的订单号 (必传)
    NSString *productCode = @"com.xxgame.sdk.demo.228"; // 商品标识(苹果商品标识)(必传)
    NSString *amount = @"228";                          // 商品金额（单位：元） (必传)
    NSString *productName = @"SDK测试商品";               // 商品名称、例：60元宝 (必传)
    NSString *serverId = @"20190927001";                // 用户游戏角色所在的服务器id (必传)
    NSString *roleId = @"100001";                       // 用户游戏角色ID (必传)
    NSString *roleName = @"角色-XXGameSDK";              // 用户游戏角色名称 (必传)
    NSString *roleLevel = @"99";                         // 用户游戏角色等级 (必传)
    NSString *extraInfo = @"2019";                       // 订单额外信息，最终将回传给游戏服务器 (选传)

    /**
     * 支付,传入订单模型
     * 支付结果通过代理方法surgeMileAlternateInnerWater:返回 YES为成功，NO为失败
     */
    [CupRotate launchingSindhiChinaMiterThe:cpOrderId
             programClampCode:productCode
                  oldTapsRole:amount
             absoluteRingName:productName
                appendWorkout:serverId
               outAuthorsInfo:extraInfo
                  capsHourArm:roleId
                siteRotorName:roleName
               areaAuditLevel:roleLevel];

### 上报角色信息（必要）

如服务端已对接此接口客户端无需对接

> 调用时机(重要!!只在以下三个场景需调用):
> 1、玩家在选择区服进入游戏时调用该接口
> 2、创建角色时调用该接口
> 3、角色升级或其他角色汇报信息发生变化时调用该接

Objective-C

    #import <BloodlessRadio/BloodlessRadio.h>

    /**
     * 必接！！！
     * 注意：确保传进的参数都为NSString类型，不接受NSNumber类型，extend字段类型为字典
     * 调用时机(重要!!只在以下两个场景需调用):
     * - 玩家在选择区服进入游戏时调用该接口。
     * - 角色升级或其他角色汇报信息发生变化时调用该接
     */
    // 区服id (必传)
    NSString *serverId = @"20190927001";
    // 区服名称 (必传)
    NSString *serverName = @"XXGame";
    // 用户游戏角色ID (必传)
    NSString *roleId = @"100001";
    // 角色名称 (必传)
    NSString *roleName = @"角色-XXGameSDK";
    // 角色等级 (必传)
    NSString *roleLevel = @"15";
    // 角色扩展信息（选填）类型：字典
    NSDictionary *extend = @{
        @"pet": @"60",          //宠物等级（5）
        @"horse": @"15",        //坐骑等级（1）
        @"power": @"10000",        //战力（100）
        @"promote": @"2",      //转职（2转）
        @"married": @"0",      //'0': 未婚, '1': 已婚
        @"liveness": @"2000",    //活跃度 (2000)
        @"hero_level": @"98",   //英雄等级(98级)
        @"guanqia": @"2",       // 关卡
        @"trumps": @[ //已激活的法宝列表
             @"fabao1",   //法宝1
             @"fabao2"    //法宝2
        ],
        @"wings": @[  //已激活的翅膀列表
             @"wing1",    //翅膀1
             @"wing2"     //翅膀2
        ],
        @"artifacts": @[  //已激活的神器列表
             @"artifact1",    //神器1
             @"artifact2",    //神器2
        ],
        //@"xxx":@"xxx"                     //其他自定义信息
        //@"xxx":@"xxx"                     //其他自定义信息
        //@"xxx":@"xxx"                     //其他自定义信息
        //...
    };

    /**上报角色信息*/
    [CupRotate displayedDecoderDublinFemaleLabeledInfo:serverId
                   radioUndoneName:serverName
                       capsHourArm:roleId
                     siteRotorName:roleName
                    areaAuditLevel:roleLevel
                       resultMedia:extend];

### 其他配置

#### 登录界面关闭接口（可选接口）

> 隐藏SDK界面右上角关闭按钮默认为：YES 隐藏状态

> 如果游戏登录界面没有登录按钮用来拉起SDK登录界面，不用调用或设置为YES，以免用户关闭后无法重新拉起登录界面

Objective-C

    #import <BloodlessRadio/BloodlessRadio.h>

    [SeeExtract malayalamBankersTaskLiftBeganUpdates:YES];

## 巨量SDK 集成

### URL Schemes 配置

#### URL Schemes = 包名

> 例如：假设一个包的包名为：com.test.example;

> 则配置对应的 URL schemes： com.test.example；

xml

    <key>CFBundleURLTypes</key>
    <array>
      <blob>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
          <string>com.test.example</string>
        </array>
      </blob>
    </array>

## 穿山甲 SDK 集成

### 工程配置

#### 添加依赖

> 工程需要在TARGETS -> Build Phases中找到Link Binary With Libraries，点击“+”，依次添加下列依赖库

- libresolv.9.tbd

- CoreML.framework

- CoreHaptics.framework

- JavaScriptCore.framework

#### SKAdNetworkItems

> 在 Info.plist 添加 SKAdNetworkItems

xml

    <key>SKAdNetworkItems</key>
    <array>
       <blob>
           <key>SKAdNetworkIdentifier</key>
           <string>58922nb4gd.skadnetwork</string>
       </blob>
        <blob>
           <key>SKAdNetworkIdentifier</key>
           <string>238da6jt44.skadnetwork</string>
       </blob>
       <blob>
           <key>SKAdNetworkIdentifier</key>
           <string>22mmun2rn5.skadnetwork</string>
       </blob>
    </array>

### CSJ功能接口

#### 激励广告

所需参数激励广告ID：holdMomentaryBandwidthFetchedSpecified（运营提供）

Objective-C

    #import <BloodlessRadio/BloodlessRadio.h>
    /*
     @param holdMomentaryBandwidthFetchedSpecified 激励广告ID
     @param extra 透传参数（研发使用）
     @param unlikely(code) 回调参数 code：
        1000:广告奖励下发
        -1000:广告奖励下发失败
        1001:广告加载成功
        -1001:广告加载失败
        1002:广告已经展示
        -1002:广告展示失败
        1003:广告被点击
        1004:广告已经关闭
        1005:广告被点击跳过
        1006:广告视频播放完成
     */
    [CupRotate alignmentFinishedYesterdayStickyTwitterPredicted:@"103814712" extra:extra unlikely:^(NSString * _Nonnull code) {
        [self demo_log:[NSString stringWithFormat:@"广告状态码=%@",code]];
        if (code.intValue == 1000) {
            [self demo_log:@"广告奖励下发"];
        }
    }];

#### 插屏广告

所需参数插屏广告ID：helloFiveAudio（运营提供）

Objective-C

    #import <BloodlessRadio/BloodlessRadio.h>
    /*
     @param helloFiveAudio 插屏广告ID <运营提供>
     @param extra 透传参数
     @param unlikely(code) 回调参数 code：
         1000:广告加载成功
         -1000:广告加载失败
         1001:广告素材加载完成
         1002:广告即将展示
         1003:广告已经展示
         -1003:广告展示失败
         1004:广告被点击
         1005:广告被点击跳过
         1006:广告即将关闭
         1007:广告已经关闭
         1008:广告视频播放完成
         1009:即将弹出广告详情页回调
         1010:奖励验证回调成功
         -1010:奖励验证回调成功
     */
    [CupRotate backwardDateBarCompressDecisionSaw:@"103845102" extra:extra unlikely:^(NSString * _Nonnull code) {
        [self demo_log:[NSString stringWithFormat:@"广告状态码=%@",code]];
    }];

## 分享 SDK 集成

### 添加 swift文件

由于SDK使用到包含swift的第三方库，所以项目中需包含一个swift文件，达到重新检查并修复模块间的依赖关系

如果Xcode工程中已经存在swift文件可不添加，否则请直接在Xcode工程中任意位置创建任意一个swift文件

### 工程配置

#### 通用链接Universal Link

配置规则：

> 在Xcode工程中，选择你的工程设置项-->选中" TARGETS "一栏对应的Target-->在" Signing & Capabilities" -->" Capability "-->搜索添加" Associated Domains "

微信：

例如：universalLink：https://79d7fe7b028474dd63d22790bd672616.share2dlink.com/

添加：applinks:79d7fe7b028474dd63d22790bd672616.share2dlink.com/

QQ：

例如：universalLink：https://79d7fe7b028474dd63d22790bd672616.share2dlink.com/qq_conn/102819929

添加：applinks:79d7fe7b028474dd63d22790bd672616.share2dlink.com/qq_conn/102819929

#### 添加依赖

> 工程需要在TARGETS -> Build Phases中找到Link Binary With Libraries，点击“+”，依次添加下列依赖库

- libz.tbd
- libsqlite3.tbd
- CoreServices.framework

#### URL Schemes 配置

配置规则：

> 在Xcode工程中，选择你的工程设置项-->选中"TARGETS"一栏对应的Target-->在"info"标签栏的-->"URL Types"

平台 | 配置URL Scheme 格式 | 举例
--- | --- | ---
QQ/Qzone | tencent+appID ，QQ+APPID的十六进制 | 如appID：100371282 最后配置：tencent100371282，QQ05FB8B52 注意appid十进制转十六进制，可以在[ 这里] 转换，如果appId转换的16进制数不够8位则在前面补0，如转换的是：5FB8B52，则最终填入为：QQ05FB8B52 注意：转换后的字母要大写
微信 | 微信的appid | 如appID：wx617c77c82218ea2c，最后配置：wx617c77c82218ea2c
抖音 | 抖音初始化的appkey | aw9ivykfjvi4hpwo

#### 权限

配置规则：

> 在Xcode工程中，选择你的工程设置项-->选中"TARGETS"一栏对应的Target-->在"info"标签栏的-->""Custom iOS Target Properties"

配置相册使用权限：

分享的图片通过相册进行跨进程共享，如需使用分享功能，还需要填写相册访问权限，在 info 标签栏中添加 Privacy - Photo Library Usage Description

> NSPhotoLibraryUsageDescription

xml

    <key>NSPhotoLibraryUsageDescription</key>
    <string>APP需要您的同意，才能访问相册选择图片使用分享功能，如禁止将无法完成分享操作操作</string>

#### 白名单配置

配置规则：

> 在Xcode工程中，选择你的工程设置项-->选中"TARGETS"一栏对应的Target-->在"info"标签栏的-->""Custom iOS Target Properties"

> 微信、QQ、抖音、TapTap

> LSApplicationQueriesSchemes

xml

    <key>LSApplicationQueriesSchemes</key>
        <array>
            <string>taptap</string>
            <string>weixin</string>
            <string>weixinULAPI</string>
            <string>weixinURLParamsAPI</string>
            <string>mqzoneopensdk</string>
            <string>mqzoneopensdkapi</string>
            <string>mqzoneopensdkapi19</string>
            <string>mqzoneopensdkapiV2</string>
            <string>mqqOpensdkSSoLogin</string>
            <string>mqqopensdkapiV2</string>
            <string>mqqopensdkapiV3</string>
            <string>wtloginmqq2</string>
            <string>mqqapi</string>
            <string>mqqwpa</string>
            <string>mqzone</string>
            <string>mqq</string>
            <string>mqqopensdkapiV4</string>
            <string>mqqopensdkminiapp</string>
            <string>douyinsharesdk</string>
            <string>douyinopensdk</string>
        </array>

### 接口调用

    /*
     * type:0-5 QQ好友｜QQ空间｜微信好友｜微信朋友圈｜抖音｜TapTap
     * title:标题
     * text:内容
     * images:图片集合,传入参数可以为单张图片信息，也可以为一个NSArray，数组元素可以为UIImage、NSString（图片路径）、NSURL（图片路径）、SSDKImage。如: @"http://www.xxgame.cn/images/logo_black.png" 或 @[@"http://www.xxgame.cn/images/logo_black.png"]
     * url: 类型NSURL 网页路径/应用路径
     *
     * 以下TapTap专用，其他平台不生效
        * groupLabelId:论坛标签 ID 最多支持 1 个
        * hashtagIds:话题 ID  最多支持 5 个，多个话题 Id 以英文逗号,分割 例如："hashtag1,hashtag2"
        * footerImages:本地图片数据数组 可选，最多支持 9 张，总大小未见苹果说明限制，但应尽量保持小
        * failUrl:设置未安装 TapTap 应用时跳转链接，推荐使用 REP 生成的游戏详情页效果链接，仅用于taptap渠道
     */

    NSInteger type = 0; // type:0-5 QQ好友｜QQ空间｜微信好友｜微信朋友圈｜抖音｜TapTap
    NSString *title = @"Demo-标题"; // 标题
    NSString *text = @"Demo-内容"; // 内容
    id images = @"https://xxgame.cn/images/banner_fj.jpg"; // 图片集合,传入参数可以为单张图片信息，也可以为一个NSArray，数组元素可以为UIImage、NSString（图片路径）、NSURL（图片路径）、SSDKImage。如: @"http://www.xxgame.cn/images/logo_black.png" 或 @[@"http://www.xxgame.cn/images/logo_black.png"]
    NSURL *url = [NSURL URLWithString:@"https://xxgame.cn"]; // 类型NSURL 网页路径/应用路径

    [CupRotate finderKilowattType:type
                            title:title
                             text:text
                           images:images
                              url:url
                     groupLabelId:nil
                       hashtagIds:nil
                     footerImages:nil
                          failUrl:nil
                         callback:^(BOOL result, NSString * _Nonnull errorMsg) {
        if (result) {
          // 成功
        }else {
          // 失败
        }
    }];