# GHOME SDK 开发手册 for IOS 国际版

版本更新说明

# 1. 前言

本文用于指导游戏开发商接入GHomeSDK国际版,文中包含客户端的接入说明.

# 2. SDK包含功能:

  • 登录功能(包含FaceBook,GameCenter,Line,苹果登录,游客模式,邮箱)
  • 账号绑定功能(包含FaceBook,GameCenterLine,苹果登录,邮箱)
  • 支付功能(除游客模式外用户登录后均可调用支付功能)
  • 账号登出功能
  • 账号注销功能
  • 分享功能
  • 本地通知功能(GHPushPlugin.framework)
  • Firebase数据上报,如果不需要请删除ghome SDK中的 GHFirebase整个文件夹里的内容(firebase插件FIRAppPlugin+firebase数据上报所需的SDK)
  • 如果需要使用苹果登录功能请开启 targets设置中添加SignInwithApple

# 3. 开发环境要求

  • 对于iOS开发者,建议使用最新版本进行开发,iOS版本需求为12.0及以上,Xcode版本15.0及以上

  • # 三方登录支持说明

    • 目前支持 G 家登录: 游客、邮箱

    • 目前支持三方登录: google、facebook、line、apple

    • 支持通过 Ghome SDK 服务端配置动态设置是否支持三方登录,并支持选择其中某几个三方登录

      !!!提示!!! 游戏接入 SDK 时,若需要使用三方登录,需配置 G 家后台三方登录渠道参数

# 3.1 引用SDK提供的Framework、资源包:

文件名 是否必须 备注
libGHomeAPI_Gi18n.a 基础库文件
BXFoundation.framework 基础库文件
GHCore.framework 基础库文件
FBAEMKit.framework Facebook sdk文件
FBSDKCoreKit_Basics.framework Facebook sdk文件
FBSDKCoreKit.framework Facebook sdk文件
FBSDKLoginKit.framework Facebook sdk文件
LineSDK.framework Line sdk文件 需设置成Embed & Sign
LineSDKObjC.framework Line sdk文件 需设置成Embed & Sign
GoogleSignIn.bundle Google sdk文件
GoogleSignIn.framework Google sdk文件
AppAuth.framework Google sdk文件
GTMAppAuth.framework Google sdk文件
GTMSessionFetcher.framework Google sdk文件
GHomeAPI.h GHome头文件
GHomeAPIConstants.h GHome头文件
GHomeCore18n.bundle GHome图片资源文件 加在游戏target中 非unityfrawork的target
GHomeLanguage.bundle GHome多语言资源文件 加在游戏target中 非unityfrawork的target
GHFirebase/Analytics/FBLPromises.framework Firebase sdk文件,如不需要Firebase功能可以删除GHFirebase文件夹
GHFirebase/Analytics/FIRAppPlugin.framework Firebase 功能文件,如不需要Firebase功能可以删除GHFirebase文件夹
GHFirebase/Analytics/FirebaseAnalytics.framework Firebase sdk文件,如不需要Firebase功能可以删除GHFirebase文件夹
GHFirebase/Analytics/FirebaseCore.framework Firebase sdk文件,如不需要Firebase功能可以删除GHFirebase文件夹
GHFirebase/Analytics/FirebaseCoreInternal.framework Firebase sdk文件,如不需要Firebase功能可以删除GHFirebase文件夹
GHFirebase/Analytics/FirebaseInstallations.framework Firebase sdk文件,如不需要Firebase功能可以删除GHFirebase文件夹
GHFirebase/Analytics/GoogleAppMeasurement.framework Firebase sdk文件,如不需要Firebase功能可以删除GHFirebase文件夹
GHFirebase/Analytics/GoogleUtilities.framework Firebase sdk文件,如不需要Firebase功能可以删除GHFirebase文件夹
GHFirebase/Analytics/nanopb.framework Firebase sdk文件,如不需要Firebase功能可以删除GHFirebase文件夹
GHShare/FBSDKShareKit.framework Facebook share sdk文件,如不需要分享功能可以删除GHShare文件夹
GHShare/GHSharePlugin.framework 分享基础文件,如不需要分享功能可以删除GHShare文件夹
GHPushPlugin.framework 本地推送功能基础文件,如不需要本地推送可以删除

3.2 修改工程配置

1.注:确保 Build Settings -> Build Options-> always embed swift standard libraries 设置为 YES

2.在工程配置里头,找到Linking部分,修改Other Linker Flags,添加内容:-ObjC 并且ENABLE_BITCODE 设置为NO

3.在info.plist中 添加AgreementDefultStatus bool类型,如果为YES表示登录页面默认勾选协议,NO 默认不勾选

4.如果不使用ghome中的firebase数据上报功能,删除GHFirebase整个文件夹里的内容(firebase数据上报插件FIRAppPlugin+firebase数据上报所需的SDK)即可;如果您的项目已经引入了firebase数据上报相关SDK,删除GHFirebase中重复的SDK即可

5.在项目Info.plist文件中添加scheme白名单 LSApplicationQueriesSchemes:

fbapi 
fb-messenger-share-api
fbauth2 
fbshareextension 
lineauth2 
line3rdp.$(PRODUCT_BUNDLE_IDENTIFIER)  
whatsapp
1
2
3
4
5
6
7

6.在URLType中添加 URLSchemes

fbxxxxxxxxx(你的FaceBookSchemes)
line3rdp.$(PRODUCT_BUNDLE_IDENTIFIER)
GIDClientID倒序
例如GIDClientID是:
684195202665-lb844hurulnnc3n7abgqcjpucku6bpa6.apps.googleusercontent.com
倒序是:
com.googleusercontent.apps.684195202665-lb844hurulnnc3n7abgqcjpucku6bpa6
1
2
3
4
5
6
7
  1. Facebook 参数设置 在项目Info.plist文件中添加
FacebookDisplayName : 你的项目名称
FacebookAppID : 你的FaceBookID
FacebookClientToken:facebook管理后台可以查到
1
2
3

8.line 登录

在info.plist中 添加LineChannelID string类型,表示Line 的 ChannelID

9.Google 登录

在info.plist中 添加GIDClientID string类型,Google登录的 ClientID

10 在项目Info.plist文件中添加

NSAppTransportSecurity:NSAllowsArbitraryLoads YES

11.在项目Info.plist文件中添加sdk对应域名:

18nBaseUrl: 登录host

18nPayBaseUrl:支付host

18nWebLoginBaseUrl:登录Web的host

18nWebPayBaseUrl:支付Web的host

18nLogBaseUrl:日志host

根据发布国家和地区配置不同的host,详询GHomeSDK产品  以下内容仅示例:

新加坡地区域名
18nBaseUrl登录:abroad-sin.shengqugames-corp.com
18nPayBaseUrl支付:abroad-sin-pay.shengqugames-corp.com
18nWebLoginBaseUrl登录Web的host:abroad-sin-wlogin.shengqugames-corp.com
18nWebPayBaseUrl支付Web的host:abroad-sin-wpay.shengqugames-corp.com
18nLogBaseUrl日志:reportsk-gg.web.sdo.com
1
2
3
4
5
6

更多枚举信息,点这里

12.添加依赖库

StoreKit.framework  设置成Optional
SystemConfiguration.framework
CoreTelephony.framework
CFNetwork.framework
AuthenticationServices.framework 设置成Optional
CoreText.framework
Foundation.framwork
Accelerate.framework
CoreFoundation.framework
ImageIO.framework
MediaToolbox.framework

libsqlite3.tbd
libresolv.tbd
libz.tbd
libc++.tbd
libiconv.tbd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

13.在 signing&capabilities中 添加 In-app Purchase, Sign in with Apple 功能

14.AppDelegate.mm中添加一下方法(Unity导出工程叫做UnityAppController.mm)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[GHomeAPI sharedGHome] application:application didFinishLaunchingWithOptions:launchOptions];
    return YES;
}

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
    return [[GHomeAPI sharedGHome] application:app openURL:url options:options];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    return [[GHomeAPI sharedGHome] application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [[GHomeAPI sharedGHome] applicationDidEnterBackground:application];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    [[GHomeAPI sharedGHome] applicationWillEnterForeground:application];  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 4. 基础功能

# 4.1. SDK初始化接口

  • 初始化接口定义
/**
 * 初始化
 * @param delegate       委托对象
 *        appId          游戏ID
 */
- (void)initialize:(id<GHomeAPIInitializeDelegate>)delegate
             appId:(NSString*)appId;
1
2
3
4
5
6
7
  • 初始化接口调用示例
[[GHomeAPI sharedGHome] initialize:self appId:@"1000"];
1
  • 初始化接口回调示例
- (void)initializeResult:(NSInteger)resultCode resultMsg:(NSString*)resultMsg
{
    showAlertView(@"initializeResult code[%@] msg[%@]", @(resultCode), resultMsg);
}
1
2
3
4
  • 初始化接口回调说明:

    当resultCode为 0 时表示成功。
    当resultCode为其他值时均表示失败,resultMsg为失败信息描述。
    当resultCode为 0 时方可进行其他SDK操作。

  • 初始化可以在AppDelegate中调用也可以在ViewController中调用,具体什么位置调用由接入方自行决定,只有保证在初始化成功后才能调用login接口

# 4.2 客户端登录接口

  • 登录接口定义
/**
 * 登录
 * @param delegate       委托对象
 */
- (void)login:(id<GHomeAPILoginDelegate>)delegate;
1
2
3
4
5
  • 登录接口说明:
    包含自动登录功能,调用者可直接调用登录接口无需做票据存储。

  • 登录接口调用示例:

[[GHomeAPI sharedGHome] login:self];
1
  • 登录接口回调示例
/**
 * 登录结果回调
 * @param resultCode   返回码
 * @param resultMsg   返回信息
 * @param ticket   票据
 * @param userId   用户ID
 * @param isGuest    是否游客
 * @param isBinded    是否绑定
 * @param loginType      登录类型  0:游客  588:邮箱 502:Google 503:Facebook 504:Appleid 505:TWitter(iOS暂不支持) 506:Line
 */
- (void)loginResult:(NSInteger)resultCode resultMsg:(NSString *)resultMsg ticket:(NSString *)ticket userId:(NSString *)userId isGuest:(BOOL)isGuest isBinded:(BOOL)isBinded loginType:(NSInteger)loginType
{
    showAlertView(@"loginResult code[%@] msg[%@] ticket[%@] useId[%@] isGuest[%@] isBinded[%@]", @(resultCode), resultMsg, ticket, userId, @(isGuest), @(isBinded);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 登录接口回调说明:
    当resultCode为 0 时表示成功,回调值有效。 当resultCode不为0时,游戏可以显示错误内容,然后再次调用登录接口,让用户继续登录。

# 4.3 客户端绑定接口

/**
 *绑定接口
 */
- (void)bindAccountWithCallback:(void (^)(NSInteger code,NSString *msg, NSDictionary *dic))callback;
1
2
3
4
  • 绑定接口说明: 游客模式登录后方可调用该功能(绑定账号包含FaceBook,GameCenter)。 当code为 0 时表示绑定成功。

# 4.4 客户端登出接口

  • 登出接口定义
/**
 * 注销(切换账号)
 * @param delegate       委托对象
 */
- (void)logout:(id<GHomeAPILogoutDelegate>)delegate;
1
2
3
4
5
  • 登出接口调用示例
[[GHomeAPI sharedGHome] logout:self];
1
  • 登出接口回调示例
- (void)logoutResult:(NSInteger)resultCode resultMsg:(NSString*)resultMsg
{
    showAlertView(@"logoutResult code[%@] msg[%@]", @(resultCode), resultMsg);
}
1
2
3
4
  • 登出接口回调说明
    当resultCode 为 0 时表示成功。
    当resultCode 为其他值时表示失败,resultMsg为失败信息描述。

# 4.5 客户端注销账号接口

  • 注销接口定义
/**
 * 注销账号
 * @param delegate       委托对象
 */
- (void)unregister:(id <GHomeAPIUnregisterDelegate>)delegate;
1
2
3
4
5
  • 注销接口调用示例
[[GHomeAPI sharedGHome] unregister:self];
1
  • 注销接口回调示例
- (void)unregisterResult:(NSInteger)resultCode resultMsg:(NSString *)resultMsg
{
    showAlertView(@"logoutResult code[%@] msg[%@]", @(resultCode), resultMsg);
}
1
2
3
4
  • 注销接口回调说明
    当resultCode 为 0 时表示成功。
    当resultCode 为其他值时表示失败,resultMsg为失败信息描述。

# 4.6 扫码接口

使用扫码功能需申请摄像头权限,在info.plist文件中增加Privacy - Camera Usage Description

  • 扫码接口定义
/**
 * 扫码
 * @param delegate       委托对象
 */
- (void)scanQRCode:(id <GHomeAPIScanQRCodeDelegate>)delegate;
1
2
3
4
5
  • 扫码接口调用示例
[[GHomeAPI sharedGHome] scanQRCode:self];
1
  • 扫码接口回调示例
- (void)scanQRCodeResult:(NSInteger)resultCode resultMsg:(NSString *)resultMsg
{
    showAlertView(@"scanQRCodeResult code[%@] msg[%@]", @(resultCode), resultMsg);
}
1
2
3
4
  • 扫码接口回调说明
    当resultCode 为 0 时表示成功。
    当resultCode 为其他值时表示失败,resultMsg为失败信息描述。

# 5. 账号功能

# 5.1. 账号体系说明

  • 注册&登录原理

    1. 在游戏登录界面打开SDK注册&登录界面;

    2. 用户完成注册&登录之后,SDK把用户id和ticket票据返回游戏;

    3. 游戏如果有服务器,需要把客户端获取到ticket票据发送到"登录票据验证接口"进行验证,然后把返回的用户信息(用户id和账号)保存到游戏服务器;

  • 注册&登录时线图
    IOS6

# 6. 支付功能

# 6.1 支付原理说明

  • 支付原理

    1. 游戏客户端发起支付请求;

    2. SDK服务器收到请求,并发送至第三方支付;

    3. 第三方支付成功收费以后通知SDK服务器,再由SDK服务器通知游戏服务器发货至游戏,需要游戏提供"订单通知接口"进行接收;

  • 支付时线图

    IOS7

  • 注意:如果要用SDK提供的demo进行支付测试。那么要把相关证书、Bundle ID 替换成你的开发者证书与相应的Bundle ID。(支付只支持非越狱的真机)。

  • Itunes app设置请参考:

    https://developer.apple.com/library/mac/technotes/tn2259/_index.html#//apple_ref/doc/uid/DTS40009578-CH1-ITUNES_CONNECT

  • itunes product 设置请参考:

    https://developer.apple.com/library/mac/documentation/LanguagesUtilities/Conceptual/iTunesConnectInAppPurchase_Guide/Chapters/CreatingInAppPurchaseProducts.html#//apple_ref/doc/uid/TP40013727-CH3-SW1

# 6.2 客户端支付相关接口

# 1 支付接口
/**
 * 显示支付页面
 * @param delegate       委托对象
 *        productId      产品ID
 *        areaId         区ID
 *        gameOrderId    游戏订单ID
 *        extendInfo     附加参数
 */
- (void)pay:(id<GHomeAPIPayDelegate>)delegate
  productId:(NSString*)productId
     areaId:(NSString*)areaId
gameOrderId:(NSString*)gameOrderId
 extendInfo:(NSString*)extendInfo;

 /**
* 正常支付和补单支付页面,补退单回调时候不会返回退补单列表信息
* @param delegate       委托对象
*       productId      产品ID
*       areaId         区ID
*       gameOrderId    游戏订单ID
*                isRepair       YES表示 补单支付、gameOrderId 需要传入 supplementOrderList数组中的payOrderId
*       extendInfo     附加参数
*/
- (void)pay:(id <GHomeAPIPayDelegate>)delegate
  productId:(NSString *)productId
     areaId:(NSString *)areaId
gameOrderId:(NSString *)gameOrderId
   isRepair:(BOOL)isRepair
 extendInfo:(NSString *)extendInfo;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  • 支付接口调用示例
[[GHomeAPI sharedGHome] pay:self productId:@"p0001" areaId:@"1" gameOrderId:@"abc123" extendInfo:nil];

[[GHomeAPI sharedGHome] pay:self productId:@"p0001" areaId:@"1" gameOrderId:@"abc123" isRepair:YES extendInfo:nil];
1
2
3
  • 支付接口回调示例
//支付回调方法根据需要选择其中之一即可

//
- (void)payResult:(NSInteger)resultCode resultMsg:(NSString*)resultMsg
{
    showAlertView(@"payResult code[%@] msg[%@]", @(resultCode), resultMsg);
}
//iOS 6.3.0.0以及之后的版本支付时候不再返回补缴数据,如支付过程中存在需要补缴数据自动拉起SDK内部补单页面
//当 resultCode == -10310522 时候 表示当前用户需要补退单,此时infoDict会返回需要补单的信息 需要在补完所有退单之后才能购买
//infoDict 中字段示例
/***
{
    areaId = 2;//当前的areaId
    ext = testExt;//当前的ext
    gameOrderId = p1234;//当前的gameOrderId
    orderType = 1;//当前的orderType
    productId = "com.snda.gameplus.test.3";//当前的productId
    isRepair = 1 // NO表示正常下单,YES表示补退单
    //supplementOrderList 退补单数据
    supplementOrderList =     (
                {
            appMid = 10529277;
            areaId = 2;
            gameOrderId = p1234; //游戏正常支付时候传入的gameOrderId
            payChannelCode = ios;
            payOrderNo = MP010178040015230417164618000001; //在补单支付时候gameOrderId传入该字段
            productId = "com.snda.gameplus.test.3";
            priceLocale = "CNY"; //货币类型
            priceAmount = 6;//金额

        },
                {
            appMid = 10529277;
            areaId = 2;
            gameOrderId = p1234;
            payChannelCode = ios;
            payOrderNo = MP010178040015230417164552000001;
            productId = "com.snda.gameplus.test.3";
            priceLocale = "CNY"; //货币类型
            priceAmount = 6;//金额
        })
}
**/

- (void)payResult:(NSInteger)resultCode resultMsg:(NSString *)resultMsg productId:(NSString *)productId info:(NSDictionary *)info {
    showAlertView(@"payResult code[%@] msg[%@] productId[%@] infoDict[%@]", @(resultCode), resultMsg, productId, info);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  • 支付接口回调说明
    当resultCode 为 0 时表示成功。
    当resultCode 为其他值时表示失败,resultMsg为失败信息描述。
# 2 查询商品在AppStore中的信息
/**
* 根据productId 获取商品的详细信息
* @param delegate       委托对象
*       productIds      产品ID
*/
- (void)getProductsInfo:(id <GHomeAPIGetProductsInfoDelegate>)delegate
             productIds:(NSSet<NSString *> *)productIds;
1
2
3
4
5
6
7
  • 查询商品接口调用示例
[[GHomeAPI sharedGHome] getProductsInfo:self productIds:[NSSet setWithArray:@[@"com.snda.gameplus.test",@"com.snda.gameplus.test"]]];
1
  • 查询商品接口回调示例
- (void)getProductsInfoResult:(NSInteger)resultCode resultMsg:(NSString *)resultMsg products:(NSArray<SKProduct *> *)products {
    showAlertView(@"getProductsInfoResult code[%@] msg[%@] products[%@]", @(resultCode), resultMsg,products);
}
1
2
3
  • 查询商品接口回调说明

    当调用接口中productIds中有无效的商品时,在回调结果products会过滤掉

  • 支付接口回调说明
    当resultCode 为 0 时表示成功。
    当resultCode 为其他值时表示失败,resultMsg为失败信息描述。

# 3 查询退单情况
/**
* 查询是否有退单
* @param delegate       委托对象
*/
- (void)querySupplementOrderList:(id<GHomeAPIQuerySupplementDelegate>)delegate;
1
2
3
4
5
  • 查询退单接口调用示例
[[GHomeAPI sharedGHome] querySupplementOrderList:self];
1
  • 查询退单接口回调示例
- (void)querySupplementOrderListResult:(NSInteger)resultCode resultMsg:(NSString *)resultMsg info:(NSDictionary *)info{
    showAlertView(@"querySupplementOrderListResult code[%@] msg[%@] products[%@]", @(resultCode), resultMsg,info);
}

//info 中字段示例
/***
{
    supplementOrderList =     (
                {
            appMid = 10529277;
            areaId = 2;
            gameOrderId = p1234; //游戏正常支付时候传入的gameOrderId
            payChannelCode = ios;
            payOrderNo = MP010178040015230417164618000001; //在补单支付时候gameOrderId传入该字段
            productId = "com.snda.gameplus.test.3";
            priceLocale = "CNY"; //货币类型
            priceAmount = 6;//金额

        },
                {
            appMid = 10529277;
            areaId = 2;
            gameOrderId = p1234;
            payChannelCode = ios;
            payOrderNo = MP010178040015230417164552000001;
            productId = "com.snda.gameplus.test.3";
            priceLocale = "CNY"; //货币类型
            priceAmount = 6;//金额
        })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  • 查询商品接口回调说明

    回调结果中的info数据结构同支付接口

# 7. firebase接入:

到firebase官网下载项目对应GoogleService-Info.plist文件放置游戏工程plist文件旁 IOS4

# 8. SDK返回code描述:

具体可参见GHomeAPIConstants.h 和 GHomePayConstant.h

  • 获取设备唯一标示接口调用示例
NSString* deviceString = [[GHomeAPI sharedGHome] deviceId];
1

# 9. 附录A:服务器端签名算法

  • 参数说明:

    1. timestamp为调用接口时的unix时间戳(精确到秒)

    2. sequence为请求序列号(游戏服务器端需要保证两次调用接口生成的sequence不重复)

  • 签名算法:

    1. 调用方首先需要将请求的参数根据参数的key(ASCII码值)进行升序排序,为空参数不参与签名

    2. 将排序好的接口请求参数和参数值按key=val&key2=val2…这样得格式拼装成一个字符串,并在最后加上与APPID对应的APPKEY

    3. 对上述拼接好的字符串进行md5编码,获得最终的签名串

# 10. 扩展功能

# 10.1. 客户端获取游戏区服列表接口

  • 获取区服信息接口定义
/**
 * 获取区服信息
 * @param delegate       委托对象
 */
- (void)getAreaConfiguration:(id<GHomeAPIGetAreaConfigrationDelegate>)delegate;
1
2
3
4
5
  • 获取区服信息接口调用示例
[[GHomeAPI sharedGHome] getAreaConfiguration:self];
1
  • 获取区服信息接口回调示例
- (void)getAreaConfigrationResult:(NSInteger)resultCode resultMsg:(NSString*)resultMsg info:(NSDictionary*)info
{
    showAlertView(@"getAreaConfigrationResult code[%@] msg[%@] info[%@]", @(resultCode), resultMsg, info);
}
1
2
3
4
  • 获取区服信息接口回调说明
    当resultCode 为 0 时表示成功,返回info值。
    当resultCode 为其他值时表示失败,resultMsg为失败信息描述,info值无效。
  info[{
        message =         (
                        {
                "area_code" = 1;
                "name" = "\/U5996\/U7cbe\/U4e4b\/U6e56";
                "notify_url" = "http://qa.dev.mygm.sdo.com/test/gamenotify";
            }
        );
        result = 0;    //当result =0时表示成功
}]
1
2
3
4
5
6
7
8
9
10

# 10.2. 客户端获取游戏商品列表接口

  • 获取支付产品信息接口定义
/**
 * 获取支付产品信息
 * @param delegate       委托对象
 */
- (void)getProductConfiguration:(id<GHomeAPIGetProductConfigrationDelegate>)delegate;
1
2
3
4
5
  • 获取支付产品信息接口调用示例
[[GHomeAPI sharedGHome] getProductConfiguration:self];
1
  • 获取支付产品信息接口回调示例
- (void)getProductConfigurationResult:(NSInteger)resultCode resultMsg:(NSString*)resultMsg info:(NSDictionary*)info
{
    showAlertView(@"getProductConfigurationResult code[%@] msg[%@] info[%@]", @(resultCode), resultMsg, info);
}
1
2
3
4
  • 获取支付产品信息接口回调说明

    当resultCode 为 0 时表示成功,返回info值。
    当resultCode 为其他值时表示失败,resultMsg为失败信息描述,info值无效。

  info[{
        message =         (
                        {
                "item_name" = 10mc;
                "money" = "6.00";
                "product_code" = "com.product.tenGold";
                "type":1  // 0:Android游戏,1:IOS游戏,2:Android和IOS游戏
            },
                        {
                "item_name" = 10mc;
                "money" = "0.01";
                "product_code" = p0001;
                "type":2  // 0:Android游戏,1:IOS游戏,2:Android和IOS游戏
            }
        );
        result = 0;     //result = 0时表示成功
}]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 10.3. 客户端获取一次性登录票据接口

  • 获取票据接口定义
/**
 * 获取票据,登录后有效
 * @param delegate       委托对象
 *        appId          游戏ID
 *        areaId         区ID
 */
- (void)getTicket:(id<GHomeAPIGetTicketDelegate>)delegate
            appId:(NSString*)appId
           areaId:(NSString*)areaId;
1
2
3
4
5
6
7
8
9
  • 获取票据接口调用示例
[[GHomeAPI sharedGHome] getTicket:self appId:@"1000" areaId:@"1"];
1
  • 获取票据接口回调示例
- (void)getTicketResult:(NSInteger)resultCode resultMsg:(NSString*)resultMsg ticket:(NSString*)ticket
{
    showAlertView(@"getTicketResult code[%@] msg[%@] ticket[%@]", @(resultCode), resultMsg, ticket);
}
1
2
3
4
  • 获取票据接口回调说明

    当resultCode 为 0 时表示成功,返回ticket值。
    当resultCode 为其他值时表示失败,resultMsg为失败信息描述,ticket值无效。

# 11 分享功能

  • 支持的分享渠道

    渠道码 渠道信息 GHShareChannel枚举信息 备注
    0 系统分享 GHShareChannelSystem 使用苹果系统自带的分享功能(Share Extension),支持分享图片、分享链接、分享文本
    1 Facebook分享 GHShareChannelFacebook 集成了Facebook分享SDK,支持分享图片、分享链接,不支持纯文本分享
    2 Messenger分享 GHShareChannelMessenger 集成了Facebook-messenger分享SDK,支持分享图片、分享链接,不支持纯文本分享
    3 WhatsApp分享 GHShareChannelWhatsApp 通过Custom URL Scheme与WhatsApp进行信息通信,支持分享链接、分享文本,由于Custom URL Scheme不支持图片,图片分享会走系统分享的方式
  • 项目配置

  • 分享

    /// 获取GHShareService对象
    + (GHShareService *)shareInstance;
    
    /// 分享文本 Facebook和messenger渠道不支持纯文本分享
    - (void)shareTextWithChannel:(GHShareChannel)channel
                            text:(NSString *)text
               completionHandler:(GHShareCompletionHandler)completionHandler;
    
    /// 分享图片
    /// Facebook特殊要求:1、照片大小必须小于 12MB   2、用户需要安装 7.0 或更高版本的原生 iOS 版 Facebook 应用
    /// - Parameters:
    ///   - channel: 渠道
    ///   - image: 图片
    ///   - completionHandler: 回调
    - (void)shareImageWithChannel:(GHShareChannel)channel
                            image:(UIImage *)image
                completionHandler:(GHShareCompletionHandler)completionHandler;
    
    /// 分享链接
    /// - Parameters:
    ///   - channel: 渠道
    ///   - title: 标题 非必填,如果不需要请填空字符串 @""
    ///   - urlString: 链接
    ///   - completionHandler: 回调
    - (void)shareURLWithChannel:(GHShareChannel)channel
                          title:(NSString *)title
                      urlString:(NSString *)urlString
              completionHandler:(GHShareCompletionHandler)completionHandler;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28

    示例

    /// 导入头文件
    #import <GHSharePlugin/GHShareService.h>
    
    /// 分享url
    - (void)shareURL
    {
        NSString * urlString = @"https://www.baidu.com?wd=哈哈";
        __weak typeof(self) weakSelf = self;
        [[GHShareService shareInstance] shareURLWithChannel:GHShareChannelWhatsApp title:@"这是标题" urlString:urlString completionHandler:^(GHShareChannel channel, GHShareResultCode resultCode) {
            [weakSelf handleShareResultWithChannel:channel resultCode:resultCode];
        }];
    }
    
    /// 处理分享结果
    - (void)handleShareResultWithChannel:(GHShareChannel)channel resultCode:(GHShareResultCode)resultCode {
        NSString * channelString = @"";
        switch (channel) {
            case 0:
                channelString = @"系统分享";
                break;
            case 1:
                channelString = @"Facebook分享";
                break;
            case 2:
                channelString = @"messenger分享";
                break;
            case 3:
                channelString = @"WhatsApp分享";
                break;
            default:
                channelString = @"未知渠道";
                break;
        }
    
        NSString * msg = @"";
        switch (resultCode) {
            case 0:
                msg = @"分享成功";
                break;
            case 10001:
                msg = @"取消分享(由于系统限制,系统分享渠道中,选择messenger,无论分享是否成功,都会返回取消)";
                break;
            case 10002:
                msg = @"分享文本是空,请检查是否填写分享文本";
                break;
            case 10003:
                msg = @"分享链接是空,请检查是否填写分享链接;或者分享链接格式不符合规范";
                break;
            case 10004:
                msg = @"分享图片是空,请检查是否选取了分享图片";
                break;
            case 10005:
                msg = @"当前渠道不支持此分享类型,比如,Facebook不支持纯文本分享";
                break;
            case 10006:
                msg = @"当前渠道对应APP未安装,必须安装对应APP才可以分享";
                break;
            case 100090:
                msg = @"未知渠道,请检查:系统分享==0;Facebook分享==1;messenger分享==2;WhatsApp分享==3";
                break;
            case 1000999:
                msg = @"分享失败";
                break;
            default:
                break;
        }
    
        NSLog(@"分享结果code: %ld   渠道: %ld   msg: %@", resultCode, channel, msg);
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
  • 分享结果错误码

    错误码 错误信息 GHShareResultCode枚举信息 备注
    0 成功 GHShareResultCodeSuccess
    10001 取消 GHShareResultCodeCancel 由于系统限制,系统分享渠道中,选择了messenger,无论分享是否成功,都会返回此错误码
    10002 分享文本是空 GHShareResultCodeTextNull 请检查分享文本是否是空
    10003 分享链接是空或者链接格式不正确 GHShareResultCodeURLNull 注意URL编码规范,尽量是RFC3986规定字符
    10004 分享图片是空 GHShareResultCodeImageNull 请检查分享的图片是否是空
    10005 当前渠道不支持此分享类型 GHShareResultCodeDisableShareType Facebook和Messenger不支持纯文的分享
    10006 当前渠道对应APP未安装 GHShareResultCodeChnnelNotInstalled 由于第三方APP限制,无法完全准确判断APP是否安装,在分享参数不符合规范的时候,也可能会返回此错误码
    100090 未知渠道 GHShareResultCodeUnknownChannel 不支持的渠道
    1000999 分享失败 GHShareResultCodeUnknownError 常见于系统分享功能不支持或者第三方平台内部分享错误。参考常见问题 (opens new window)。Facebook和Messenger分享,请同时检查项目配置 (opens new window)
  • 常见问题

    • 注意】由于系统和第三方APP限制,无法完全准确判断分享的结果,GHShareResultCode错误码仅供参考

    • Facebook、Messenger、WhatsApp 这三个APP均不支持文字、链接、图片这三种内容同时分享

    • 分享链接到Facebook和Messenger的时候,Facebook和Messenger会自动解析链接,有概率会用解析出来的图片作为封面图,具体规则未知

    • WhatsApp Custom URL Scheme 分享,分享只支持纯文字,如果要分享其他内容,比如图片,会走系统分享渠道

    • WhatsApp Custom URL Scheme 分享,如果安装了WhatsApp,扔提示APP未安装,请检查工程的Info.plist中的Queried URL Schemes中,是否增加whatsapp

    • Facebook SDK分享,图片分享要求:

      1、照片大小必须小于 12MB

      2、用户需要安装 7.0 或更高版本的原生 iOS 版 Facebook 应用

    • Messenger SDK分享,需要安装Messenger应用

# 12 本地通知

  • 初始化推送通知服务

    /// 初始化推送通知服务
    /// - Parameters:
    ///   - notificationCenterDelegate: UNUserNotificationCenterDelegate 代理
    ///   - completionHandler: 结果回调
    - (void)registerNotificationWithNotificationCenterDelegate:(id<UNUserNotificationCenterDelegate>)notificationCenterDelegate
                                             completionHandler:(void(^)(GHPushResultCode resultCode))completionHandler;
    
    1
    2
    3
    4
    5
    6

    由于苹果的本地通知服务也是基于苹果的推送功能来实现的,所以在设置本地通知之前,必须要初始化推送服务,向用户申请系统通知权限

    如果不需要本地通知服务,可以将GHPushPlugin.framework删除 注意要尽可能早的初始化推送服务,一般放在APP的AppDelegate中初始化

    示例:

    /// 导入头文件
    #import <GHPushPlugin/GHPushService.h>
    
    /// 遵守协议
    <UNUserNotificationCenterDelegate>
    
    /// 初始化推送服务
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        [[GHPushService shareInstance] registerNotificationWithNotificationCenterDelegate:self completionHandler:^(GHPushResultCode resultCode) {
            NSString * msg = @"获取到推送权限";
            if (resultCode == GHPushResultCodeNotificationDisabled) {
                msg = @"没有推送权限";
            }
            NSLog(@"code: %ld   msg: %@", (long)resultCode, msg);
        }];
        return YES;
    }
    
    /// 实现<UNUserNotificationCenterDelegate>协议方法
    
    /// APP在前台的时候的收到通知
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
        UNNotificationContent *content = notification.request.content;
        NSLog(@"APP在前台的时候的收到通知 推送 title:%@  subtitle: %@   body: %@", content.title, content.subtitle, content.body);
        NSString * noticeId = notification.request.identifier;
        NSLog(@"APP在前台的时候的收到通知 推送id:%@", noticeId);
        NSDictionary * pushInfo = notification.request.content.userInfo;
        NSLog(@"APP在前台的时候的收到通知 userInfo:%@", pushInfo);
        // APP在前台的时候的处理,可自定义是否显示未读消息角标、声音、消息横幅
        // UNNotificationPresentationOptionBadge 显示角标,本地通知目前不显示角标
        // UNNotificationPresentationOptionSound 播放声音
        // UNNotificationPresentationOptionAlert 显示横幅
        completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert);
    }
    
    /// 点击通知横幅
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
        UNNotificationContent *content = response.notification.request.content;
        NSString * contentString = [NSString stringWithFormat:@"点击通知横幅 推送 \ntitle:%@  \nsubtitle: %@   \nbody: %@", content.title, content.subtitle, content.body];
        NSLog(@"%@", contentString);
    
        NSString * noticeId = response.notification.request.identifier;
        NSLog(@"点击通知横幅 推送id:%@", noticeId);
    
        NSDictionary * pushInfo = response.notification.request.content.userInfo;
        NSLog(@"点击通知横幅 userInfo:%@", pushInfo);
    
        UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"点击通知横幅" message:contentString preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction * actionBtn = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
        }];
        [alert addAction:actionBtn];
        [self.window.rootViewController presentViewController:alert animated:YES completion:nil];
    
        completionHandler();
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
  • 设置本地推送通知

    • 当前时间多少秒后开始推送通知

      /// 本地通知 - 当前时间多少秒后开始推送
      /// - Parameters:
      ///   - noticeId: 推送id,必传,注意保持唯一性,不同的推送事件要用不同的id,相同的id会覆盖前一次的推送设置,可以在 `UNUserNotificationCenterDelegate` 回调中获取
      ///   - title: 标题
      ///   - subtitle: 副标题
      ///   - body: 内容   如果 title subtitle body 都传空,不会显示通知横幅
      ///   - userInfo: 自定义消息内容,可以在 `UNUserNotificationCenterDelegate` 回调中获取
      ///   - imageFilePath: 图片路径 注意:必须要是本地图片的路径
      ///   - timeInterval: 时间,单位:秒,如果想要立马推送,传0即可,double类型
      ///   - repeats: 是否重复推送。 如果需要重复推送,时间必须大于60秒,否则重复不会生效,只会推送一次
      ///   - completionHandler: 结果回调
      - (void)addLocalTimeIntervalNotificationWithID:(NSString *)noticeId
                                               title:(NSString *)title
                                            subtitle:(NSString *)subtitle
                                                body:(NSString *)body
                                            userInfo:(NSDictionary *)userInfo
                                       imageFilePath:(NSString *)imageFilePath
                                        timeInterval:(NSTimeInterval)timeInterval
                                             repeats:(BOOL)repeats
                                   completionHandler:(GHLocalPushCompletionHandler)completionHandler;
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
    • 固定时间推送通知

      /// 本地通知 - 固定时间推送
      /// - Parameters:
      ///   - noticeId: 推送id,必传,注意保持唯一性,不同的推送要用不同的id,相同的id会覆盖前一次的推送设置,可以在 `UNUserNotificationCenterDelegate` 回调中获取
      ///   - title: 标题
      ///   - subtitle: 副标题
      ///   - body: 内容  如果 title subtitle body 都传空,不会显示通知横幅
      ///   - userInfo: 自定义消息内容,可以在 `UNUserNotificationCenterDelegate` 回调中获取
      ///   - imageFilePath: 图片路径 注意:必须要是本地图片的路径
      ///   - components: 固定推送的时间。
      ///
      ///                 【注意】经过测试,发现苹果系统对于NSDateComponents有以下要求:
      ///
      ///                 1、时间单位要保持连续性,比如:x年x月x日,如果设置为x年x日,推送设置可能会失败。
      ///                 2、注意时间是24小时制
      ///                 3、weekday 默认是从周日开始,1 ~ 7,对应周日 ~ 周六
      ///                 4、weekday不要和年、月、日同时设置
      ///                 5、如果不需要某个时间单位,不设置即可,不要设置为0,比如:0月6日6时0分,应该设置为 6日6时
      ///
      ///                 eg:
      ///                 eg1:6月6号6点推送
      ///                 NSDateComponents *components = [[NSDateComponents alloc] init];
      ///                 components.month = 6
      ///                 components.day = 6;
      ///                 components.hour = 6;
      ///
      ///                 eg2:周日6点推送
      ///                 NSDateComponents *components = [[NSDateComponents alloc] init];
      ///                 components.weekday = 1;
      ///                 components.hour = 6;
      ///
      ///   - repeats: 是否重复。如果设置的时间是具体的时间,不会重复推送比如:2022年6月6号6点6分
      ///
      ///                 x分              可每小时重复
      ///                 x时x分            可每日重复
      ///                 x日x时            可每月重复
      ///                 x日x时x分          可每月重复
      ///                 x月x日            可每年重复
      ///                 x月x日x时         可每年重复
      ///                 x月x日x时x分        可每年重复
      ///                 周x x时x分         可每周重复
      ///                 周x x时           可每周重复
      ///
      ///                 如果需要测试效果,可手动修改手机时间,触发重复推送逻辑
      ///
      ///   - completionHandler: 结果回调
      - (void)addLocalCalendarNotificationWithID:(NSString *)noticeId
                                           title:(NSString *)title
                                        subtitle:(NSString *)subtitle
                                            body:(NSString *)body
                                        userInfo:(NSDictionary *)userInfo
                                   imageFilePath:(NSString *)imageFilePath
                                      components:(NSDateComponents *)components
                                         repeats:(BOOL)repeats
                               completionHandler:(GHLocalPushCompletionHandler)completionHandler;
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
    • 示例

      /// 导入头文件
      #import <GHPushPlugin/GHPushService.h>
      
      /// 当前时间多少秒后开始推送
      - (void)addLocalTimeIntervalNotification {
      
          NSString * noticeId = @"11111";
          NSString * title = @"这是title";
          NSString * subtitle = @"这是subtitle";
          NSString * body = @"这是body";
      
          NSDictionary * userInfo = @{
              @"info": @"这是扩展内容"
          };
      
          // 单位是秒,3秒后开始推送
          NSTimeInterval timeInterval = 3;
      
          __weak typeof(self) weakSelf = self;
          [[GHPushService shareInstance] addLocalTimeIntervalNotificationWithID:noticeId title:title subtitle:subtitle body:body userInfo:userInfo imageFilePath:@"" timeInterval:timeInterval repeats:NO completionHandler:^(GHPushResultCode resultCode, NSError *error) {
              [weakSelf handleAddLocalNoticeResultWithResultCode:resultCode error:error noticeId:noticeId];
          }];
      }
      
      /// 固定时间推送-年月日时分
      - (void)addLocalCalendarNotification {
      
          NSString * noticeId = @"22222";
          NSString * title = @"这是title";
          NSString * subtitle = @"这是subtitle";
          NSString * body = @"这是body";
      
          NSDictionary * userInfo = @{
              @"info": @"这是扩展内容"
          };
      
          // 6月9号20点20分推送
          NSDateComponents *components = [[NSDateComponents alloc] init];
          components.month = 6;
          components.day = 9;
          components.hour = 20;
          components.minute = 20;
      
          __weak typeof(self) weakSelf = self;
          [[GHPushService shareInstance] addLocalCalendarNotificationWithID:noticeId title:title subtitle:subtitle body:body userInfo:userInfo imageFilePath:@"" components:components repeats:NO completionHandler:^(GHPushResultCode resultCode, NSError *error) {
              [weakSelf handleAddLocalNoticeResultWithResultCode:resultCode error:error noticeId:noticeId];
          }];
      
      }
      
      /// 固定时间推送-周时分
      - (void)addLocalCalendarNotificationWeekday {
          NSString * noticeId = @"33333";
          NSString * title = @"这是title";
          NSString * subtitle = @"这是subtitle";
          NSString * body = @"这是body";
      
          NSDictionary * userInfo = @{
              @"info": @"这是扩展内容"
          };
      
          // 每周的周日20点30分推送
          NSDateComponents *components = [[NSDateComponents alloc] init];
          components.weekday = 1; // 默认是从周日开始,1 ~ 7,对应周日 ~ 周六
          components.hour = 20;
          components.minute = 30;
      
          __weak typeof(self) weakSelf = self;
          [[GHPushService shareInstance] addLocalCalendarNotificationWithID:noticeId title:title subtitle:subtitle body:body userInfo:userInfo imageFilePath:@"" components:components repeats:NO completionHandler:^(GHPushResultCode resultCode, NSError *error) {
              [weakSelf handleAddLocalNoticeResultWithResultCode:resultCode error:error noticeId:noticeId];
          }];
      }
      
      /// 处理通知设置结果
      - (void)handleAddLocalNoticeResultWithResultCode:(GHPushResultCode)resultCode error:(NSError *)error noticeId:(NSString *)noticeId {
          NSString * reason = @"成功";
          switch (resultCode) {
              case GHPushResultCodeNotificationDisabled: {
                  reason = @"没有推送权限";
              }
                  break;
              case GHPushResultCodeLocalNoticeIdNull: {
                  reason = @"推送id是空";
              }
                  break;
              case GHPushResultCodeError: {
                  reason = @"失败";
              }
                  break;
              default:
                  break;
          }
          NSLog(@"noticeId: %@ code: %ld msg: %@ error: %@", noticeId, (long)resultCode, reason, error);
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
  • 删除通知

    /// 移除某一个指定的本地通知
    /// - Parameter noticeId: 推送id
    - (void)removeTheLocalNotificationWithID:(NSString *)noticeId completionHandler:(GHLocalPushCompletionHandler)completionHandler;
    
    /// 移除某一组指定的本地通知
    /// - Parameter noticeIds: 一组推送id
    - (void)removeTheLocalNotificationWithIDArray:(NSArray<NSString *> *)noticeIds completionHandler:(GHLocalPushCompletionHandler)completionHandler;
    
    /// 移除所有本地通知
    - (void)removeAllLocalNotificationCompletionHandler:(GHLocalPushCompletionHandler)completionHandler;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  • 其他功能

    /// 获取本地通知
    /// - Parameter completionHandler: 本地通知id数组
    - (void)getPendingNotificationIDsWithCompletionHandler:(void(^)(NSArray<NSString *> *noticeIds))completionHandler;
    
    /// 判断用户是否允许接收推送通知
    /// - Parameter callback: isEnable == YES 表示打开了通知
    - (void)checkUserNotificationEnable:(void(^)(BOOL isEnable))callback;
    
    /// 打开设置页面 如果用户关闭了接收推送通知功能,该方法可以跳转到APP设置页面进行修改
    - (void)goToAppSystemSetting;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  • 错误码

    错误码 错误信息 GHPushResultCode枚举信息 备注
    0 成功 GHPushResultCodeSuccess
    20001 推送通知没有授权 GHPushResultCodeNotificationDisabled 用户关闭了当前APP的系统通知权限
    20002 本地通知-通知id为空 GHPushResultCodeLocalNoticeIdNull 请检查本地通知-通知id是否为空
    200099 失败 GHPushResultCodeError 系统错误,常见于系统功能不支持。参考常见问题 (opens new window)
  • 常见问题

    • 初始化推送服务是必须要接入的,否则通知功能不会生效;如果用户关闭的推送通知的权限,通知功能也不会生效

    • noticeId: 推送id,必传,注意保持唯一性,不同的推送要用不同的id,相同的id会覆盖前一次的推送设置

    • 如果 title subtitle body 都传空,APP在前台的时候,不会显示通知横幅

    • 如果需要带上图片,以下要求是必须的,

      可参考demo- (void)addLocalTimeIntervalNotificationWithImage方法中的实现方式

      1、图片路径必须是本地路径,只支持本地图片

      2、图片路径中的图片扩展名必须存在,需要根据扩展名来确定图片类型

    • 在调用 当前时间多少秒后开始推送 的方法时

      1、如果选择了重复推送,需要将时间设置为60秒以上,否则重复不会生效,只会推送一次

      2、时间的单位是秒

    • 在调用 固定时间推送 的方法时,苹果对于NSDateComponents的格式有要求:

      1、时间单位要保持连续性,比如:x年x月x日,如果设置为x年x日,推送设置可能会失败。 2、注意时间是24小时制 3、weekday 默认是从周日开始,1 ~ 7,对应周日 ~ 周六 4、weekday不要和年、月、日同时设置 5、如果不需要某个时间单位,不设置即可,不要设置为0,比如:0月6日6时0分,应该设置为 6日6时

      6、如果设置了一个具体的时间,重复推送会失效

      具体使用可参考demo

# 13 Unity 参考脚本(仅供参考具体看接入文档)

using UnityEditor.iOS.Xcode;
using UnityEditor;
using UnityEditor.Callbacks;
using System.IO;
using System.Collections.Generic;
using System;
using System.Xml;
using UnityEngine;   

// 打包 xcode 项目所需的配置脚本。
public class iOSConfigEditor : Editor
{
    [PostProcessBuild(999)]
    public static void OnPostProcessBuild(BuildTarget buildTarget, string path)
    {
        if (buildTarget == BuildTarget.iOS)
        {
            //编辑 pbxproject
            string projectPath = PBXProject.GetPBXProjectPath(path);
            PBXProject pbxProject = new PBXProject();
            pbxProject.ReadFromFile(projectPath);

            //string target = pbxProject.TargetGuidByName(PBXProject.GetUnityTargetName());
            string target = pbxProject.GetUnityMainTargetGuid();

            // 编辑 BuildProperty
            pbxProject.SetBuildProperty(target, "ENABLE_BITCODE", "NO");
            pbxProject.AddBuildProperty(target, "OTHER_LDFLAGS", "-ObjC");


            pbxProject.AddBuildProperty(target, "GCC_ENABLE_OBJC_EXCEPTIONS", "YES");
            pbxProject.AddBuildProperty(target, "GCC_ENABLE_CPP_EXCEPTIONS", "YES");
            pbxProject.AddBuildProperty(target, "GCC_ENABLE_CPP_RTTI", "YES");

            // 添加 依赖的系统Framework
            pbxProject.AddFrameworkToProject(target, "CoreTelephony.framework", false);
            pbxProject.AddFrameworkToProject(target, "CoreFoundation.framework", false);
            pbxProject.AddFrameworkToProject(target, "ImageIO.framework", false);
            pbxProject.AddFrameworkToProject(target, "MediaToolbox.framework", false);
            pbxProject.AddFrameworkToProject(target, "CFNetwork.framework", false);
            pbxProject.AddFrameworkToProject(target, "SystemConfiguration.framework", false);
            pbxProject.AddFrameworkToProject(target, "MediaPlayer.framework", false);
            pbxProject.AddFrameworkToProject(target, "Accelerate.framework", false);
            pbxProject.AddFrameworkToProject(target, "AuthenticationServices.framework", true);
            pbxProject.AddFrameworkToProject(target, "StoreKit.framework", true);

            // 添加 依赖的系统library
            // 这里的 Library 与 xcode 的版本密切相关,如果编译出错,可以直接在 xcode 中按需添加或者删除。
            pbxProject.AddFrameworkToProject(target, "libresolv.tbd", false);
            pbxProject.AddFrameworkToProject(target, "libz.tbd", false);

            pbxProject.AddFrameworkToProject(target, "libc++.tbd", false);
            pbxProject.AddFrameworkToProject(target, "libsqlite3.tbd", false);

            pbxProject.AddFrameworkToProject(target, "libiconv.tbd", false);


            //Firebase 需要的配置文件,参数根据firebase后台进行修改,如果不需要可以删掉
            if (!File.Exists(path + "/GoogleService-Info.plist"))
            {
                FileUtil.CopyFileOrDirectory("Assets/Plugins/iOS/GoogleService-Info.plist", path + "/GoogleService-Info.plist");
            }
            string guid = pbxProject.AddFile("GoogleService-Info.plist", "GoogleService-Info.plist");
            pbxProject.AddFileToBuild(target, guid);

            //将bundle文件添加到游戏target中
            guid = pbxProject.AddFile("Frameworks/Plugins/iOS/GHomeCore18n.bundle", "Frameworks/Plugins/iOS/GHomeCore18n.bundle");
            pbxProject.AddFileToBuild(target, guid);
            guid = pbxProject.AddFile("Frameworks/Plugins/iOS/GHomeLanguage.bundle", "Frameworks/Plugins/iOS/GHomeLanguage.bundle");
            pbxProject.AddFileToBuild(target, guid);
            //guid = pbxProject.AddFile("Frameworks/Plugins/iOS/LineSDKResource.bundle", "Frameworks/Plugins/iOS/LineSDKResource.bundle");
            //pbxProject.AddFileToBuild(target, guid);
            //guid = pbxProject.AddFile("Frameworks/Plugins/iOS/sdk_versions.bundle", "Frameworks/Plugins/iOS/sdk_versions.bundle");
            //pbxProject.AddFileToBuild(target, guid);
            //guid = pbxProject.AddFile("Frameworks/Plugins/iOS/Trident.bundle", "Frameworks/Plugins/iOS/Trident.bundle");
            //pbxProject.AddFileToBuild(target, guid);

            //添加 内购和苹果登录的支持 此脚本由于unity原因不能生效 需要在xcode工程中手动添加一下两项
            pbxProject.AddCapability(target, PBXCapabilityType.InAppPurchase);
            pbxProject.AddCapability(target, PBXCapabilityType.SignInWithApple);

            //设置unityFramework target
            //string unityFrameworkTarget = pbxProject.TargetGuidByName(PBXProject.GetUnityTargetName());
            string unityFrameworkTarget = pbxProject.GetUnityFrameworkTargetGuid();
            pbxProject.AddFrameworkToProject(unityFrameworkTarget, "Accelerate.framework", false);
            pbxProject.SetBuildProperty(unityFrameworkTarget, "ENABLE_BITCODE", "NO");
            pbxProject.AddBuildProperty(unityFrameworkTarget, "OTHER_LDFLAGS", "-ObjC");


            File.WriteAllText(projectPath, pbxProject.WriteToString());

            // 设置 info.plist
            string plistPath = path + "/Info.plist";
            PlistDocument plist = new PlistDocument();
            plist.ReadFromString(File.ReadAllText(plistPath));
            PlistElementDict rootDict = plist.root;

            //设置白名单
            PlistElementArray pArray = rootDict.CreateArray("LSApplicationQueriesSchemes");
            pArray.AddString("fbapi");
            pArray.AddString("fb-messenger-share-api");
            pArray.AddString("fbauth2");
            pArray.AddString("fbshareextension");
            pArray.AddString("twitter");
            pArray.AddString("twitterauth");
            pArray.AddString("lineauth2");
            pArray.AddString("whatsapp");
            //pArray.AddString("line3rdp.com.sdkbus.18n");
            pArray.AddString(PlayerPrefs.GetString("lineSchemeURL"));
            //设置域名 域名列表详见文档 需要跟ghome产品确认根据实际情况填写
            rootDict.SetString("18nBaseUrl", PlayerPrefs.GetString("ghome18nBaseUrl"));
            rootDict.SetString("18nPayBaseUrl", PlayerPrefs.GetString("ghome18nPayBaseUrl"));
            rootDict.SetString("18nWebLoginBaseUrl", PlayerPrefs.GetString("ghome18nLoginWebBaseUrl"));
            rootDict.SetString("18nWebPayBaseUrl", PlayerPrefs.GetString("ghome18nPayWebBaseUrl"));
            rootDict.SetString("18nLogBaseUrl", PlayerPrefs.GetString("ghome18nLogBaseUrl"));


            //设置登录首页是否默认勾选同意协议
            rootDict.SetBoolean("AgreementDefultStatus", PlayerPrefs.GetInt("agreementDefultStatus") != 0);

            //设置Line登录相关参数 需要跟ghome产品确认根据实际情况填写
            rootDict.SetString("LineChannelID", PlayerPrefs.GetString("lineChannelId"));

            //设置Google登录相关参数
            rootDict.SetString("GIDClientID", PlayerPrefs.GetString("googleGIDClientID"));

            //设置facebook 需要根据实际情况填写
            rootDict.SetString("FacebookAppID", PlayerPrefs.GetString("facebookAppID"));
            rootDict.SetString("FacebookDisplayName", PlayerPrefs.GetString("facebookDisplayName"));
            rootDict.SetString("FacebookClientToken", PlayerPrefs.GetString("facebookClientToken"));


            //设置twitter twitter登录暂时去掉了
            //rootDict.SetString("TwitterConsumerKey", PlayerPrefs.GetString("twitterConsumerKey"));
            //rootDict.SetString("TwitterConsumerSecret", PlayerPrefs.GetString("twitterConsumerSecret"));

            //设置URL scheme 回调
            pArray = rootDict.CreateArray("CFBundleURLTypes");
            //参数组成 fb + FacebookAppID  需要根据实际情况填写
            AddURLSchemes(pArray.AddDict(), "facebook", PlayerPrefs.GetString("facebookSchemeURL"));

            //参数组成 twitterkit + "-" + TwitterConsumerKey  需要根据实际情况填写
            //AddURLSchemes(pArray.AddDict(), "twitter", PlayerPrefs.GetString("twitterSchemeURL"));

            //参数组成 line3rdp + "." + bundle id  需要根据实际情况填写
            AddURLSchemes(pArray.AddDict(), "com.sdkbus.18n", PlayerPrefs.GetString("lineSchemeURL"));

            //google
            AddURLSchemes(pArray.AddDict(), "google", PlayerPrefs.GetString("googleSchemeURL"));

            File.WriteAllText(plistPath, plist.WriteToString());

        }
    }
    private static void AddURLSchemes(PlistElementDict targetElement, string urlName, string urlschemes)
    {
        targetElement.SetString("CFBundleURLName", urlName);
        targetElement.SetString("CFBundleTypeRole", "Editor");
        var appidArray = targetElement.CreateArray("CFBundleURLSchemes");
        appidArray.AddString(urlschemes);
    }

    private static void AddResourceGroupToiOSProject(string fileName, PBXProject proj, string target, string resourceDirectoryPath)
    {
        string targetFilePath = Path.Combine(resourceDirectoryPath, fileName);
        string fileGuid = proj.AddFolderReference(targetFilePath, targetFilePath);
        proj.AddFileToBuild(target, fileGuid);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
Last Updated: 5/17/2024, 3:03:14 AM