Unity Xcode方式接入sdk

入口

创建 GameAppController 类 继承 UnityAppController
并且在类的实现之前 需要 加 IMPL_APP_CONTROLLER_SUBCLASS(GameAppController),表明这个是程序的入口。UnityAppController 实现了 UIApplicationDelegate。 可以简单看下 UIApplicationDelegate 的生命周期。

例:

@interface GameAppController : UnityAppController

+ (instancetype)shareAppController;

- (UIWindow*)appWindow;
@end

实现

IMPL_APP_CONTROLLER_SUBCLASS(GameAppController)

@implementation GameAppController {

@end

Unity 与 Objective-C 交互

Unity 调用 Objective-C

#define UNITY_CS_API extern "C"

/**
  微信登陆
 */
UNITY_CS_API void OCWXLogin(){
     //objective-c 代码
}

Objective-C 调用 Unity 代码

void    UnitySendMessage(const char* obj, const char* method, const char* msg);

obj 参数 表示GameObject Name
method 参数 表示要回调的方法名
msg 参数 表示回调的方法参数

Objective-C 与 Unity 的交互要注意的是
字符串使用的是 const char* 类型,而Objective-C 中使用的是NSString* 所以需要转换
字符串作为返回值返回 需要使用 strup 函数。否则程序将闪退
返回值 不能返回null 和 nil 否则闪退。所以返回值每次增加判断,如果null和nil 就用空字符串替换

例子

// const char* 转 NSString*
static inline NSString * str_c2ns(const char*s){
    if (s) {
        return [NSString stringWithUTF8String:s];
    }else{
        return [NSString stringWithUTF8String:""];
    }
}

//NSString* 转 const char*
+ (const char *) str_ns2c:(NSString *) content{
    return [content UTF8String];
}

//返回值使用 strdup 处理, 并做检查
UNITY_CS_API const char* OCReadClipBoard(){
    NSString *contentStr = [CoreManager.sharedInstance readClipBoard];
    if (contentStr == NULL || contentStr == nil) {
        contentStr = @"";
    }
    return strdup([UnityUtility str_ns2c:contentStr]);
}

Objective-C 与 Unity 交互 有时会使用到Json 进行数据传输,Unity 中 Null 在 Objectiv-C 中解析将会报错,使用NullSafe 库解决. github地址

接入微信SDK

遇到报错
Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: '+[WXApi genExtraUrlByReq:withAppData:]: unrecognized selector sent to class

微信官方文档的解释是需要在 Other Linker Flags 中添加 -ObjC -all_load 进行处理。我加入-all_load 会导致编译报错,这个方法行不通。
首先sdk 的配置都是添加在 UnityFramework 而不是 Unity-iPhone 上。如果是老的Unity 应该只有 Unity-iPhone,那就是添加到Unity-iPhone上。

然后由于-all_load 行不通,所以用-force_load 代替。-force_load 后面需要加入libWeChatSDK.a 所在到路径作为参数
比如:
在这里插入图片描述

关于微信登录,或者分享失效,没有回调的情况,应该是漏写了调用
在这里插入图片描述

接入友盟 和 阿里支付

遇到UTDID 库冲突。这里阿里官方有解释,下载去除 UTDID 的库。 下载的地方有说明
阿里的文档让人最舒服,没遇上什么问题。

Universal Links

这个如果没有配置好,微信登录将会照成2次弹窗确认。(那种给别人加企业签的就一定会有二次弹窗,因为没有teamid)
这个比较简单,随便找一个模板,替换teamid后,上传至服务器。然后在xcode中Signing & Capabilities 中的Associated Domains 配置 applinks: 域名

打包

如果使用Unity直接到处会覆盖xcode中我们写好的代码。所以把我们接入sdk的xcode代码放入Unity项目的Plugins 文件夹的iOS文件夹中。项目没有就自己创建。并把所有的第三方库也放入其中。这样打包的时候会自动导出至xCode项目。
此外xcode项目中还有一些自定义的配置。这个需要在打包流程完成后的回调中使用代码修改。
例如

string pbxProjectPath = PBXProject.GetPBXProjectPath(locationPath);
            
            //修改 Associated Domains 设置
            ProjectCapabilityManager capabilityManager =
                new ProjectCapabilityManager(pbxProjectPath, "Unity-iPhone.entitlements", "Unity-iPhone");
            capabilityManager.AddAssociatedDomains(new string[]{"applinks:cs1.jxhappy.top"});
            
            //wifi 信息
            capabilityManager.AddAccessWiFiInformation();
            
            // 百度持续定位
            capabilityManager.AddBackgroundModes(BackgroundModesOptions.LocationUpdates);
            
            capabilityManager.WriteToFile();
            
            PBXProject pbxProject = new PBXProject();
            pbxProject.ReadFromFile(pbxProjectPath);
            
            // string xCodeFrameworkPath = "./XCodeFramework";
            //
            // DirectoryInfo directoryInfo = new DirectoryInfo(xCodeFrameworkPath);
            //
            // foreach (var directory in directoryInfo.GetDirectories())
            // {
            //     ECKAddResourceGroupToiOSProject(locationPath, pbxProject, pbxProject.GetUnityFrameworkTargetGuid(),
            //         directory.Name);
            // }
            
            // 为类使用 @try @catch NULLSafe 中使用到了;
            pbxProject.SetBuildProperty(pbxProject.ProjectGuid(),"GCC_ENABLE_OBJC_EXCEPTIONS","YES"); 
            
            //Main
            string target = pbxProject.GetUnityMainTargetGuid();
            
            pbxProject.SetBuildProperty(target,"ENABLE_BITCODE", "NO");
            pbxProject.SetBuildProperty(target,"CONFIGURATION","Release");
            pbxProject.SetBuildProperty(target,"CONFIGURATION_BUILD_DIR","$(BUILD_DIR)/$(CONFIGURATION)");
            
            //微信相关的设置 都应该设置在 pbxProject.GetUnityFrameworkTargetGuid;

            pbxProject.AddFrameworkToProject(target,"CoreGraphics.framework",false);
            pbxProject.AddFrameworkToProject(target,"QuartzCore.framework",false);
            pbxProject.AddFrameworkToProject(target,"Foundation.framework",false);
            pbxProject.AddFrameworkToProject(target,"UIKit.framework",false);
            
            string targetUnityTarget = pbxProject.GetUnityFrameworkTargetGuid();
            
            //添加framework
            
            //微信sdk
            pbxProject.AddFrameworkToProject(targetUnityTarget,"Security.framework",false);
            pbxProject.AddFrameworkToProject(targetUnityTarget,"CoreGraphics.framework",false);
            pbxProject.AddFrameworkToProject(targetUnityTarget,"WebKit.framework",false);
            
            //支付宝sdk
            pbxProject.AddFrameworkToProject(targetUnityTarget,"libc++.tbd",false);
            pbxProject.AddFrameworkToProject(targetUnityTarget,"libz.tbd",false);
            pbxProject.AddFrameworkToProject(targetUnityTarget,"SystemConfiguration.framework",false);
            pbxProject.AddFrameworkToProject(targetUnityTarget,"CoreTelephony.framework",false);
            //pbxProject.AddFrameworkToProject(targetUnityTarget,"QuartzCore.framework",false);
            //pbxProject.AddFrameworkToProject(targetUnityTarget,"CoreText.framework",false);
            //pbxProject.AddFrameworkToProject(targetUnityTarget, "CoreGraphics.framework", false);
            //pbxProject.AddFrameworkToProject(targetUnityTarget,"UIKit.framework",false);
            //pbxProject.AddFrameworkToProject(targetUnityTarget,"Foundation.framework",false);
            //pbxProject.AddFrameworkToProject(targetUnityTarget,"CFNetwork.framework",false);
            //pbxProject.AddFrameworkToProject(targetUnityTarget,"CoreMotion.framework",false);
            // pbxProject.AddFrameworkToProject(targetUnityTarget,"AlipaySDK.framework",false);
            
            //百度地图sdk
            // pbxProject.AddFrameworkToProject(targetUnityTarget,"BMKLocationKit.framework",false);
            pbxProject.AddFrameworkToProject(targetUnityTarget,"CoreLocation.framework",false);
            //pbxProject.AddFrameworkToProject(targetUnityTarget,"SystemConfiguration.framework",false);
            //pbxProject.AddFrameworkToProject(targetUnityTarget,"Security.framework",false);
            //pbxProject.AddFrameworkToProject(targetUnityTarget,"libsqlit3.0.tbd",false);
            //pbxProject.AddFrameworkToProject(targetUnityTarget, "CoreTelephony.framework", false);
            //pbxProject.AddFrameworkToProject(targetUnityTarget,"libz.tbd",false);
            pbxProject.AddFrameworkToProject(targetUnityTarget,"AdSupport.framework",false);
            
            //UMengsdk
            // pbxProject.AddFrameworkToProject(targetUnityTarget,"UMCommon.xcframework",false);
            // pbxProject.AddFrameworkToProject(targetUnityTarget,"UMCommonLog.framework",false);
            // pbxProject.AddFrameworkToProject(targetUnityTarget,"UMDevice.xcframework",false);
            // pbxProject.AddFrameworkToProject(targetUnityTarget,"UMRemoteConfig.framework",false);
            // pbxProject.AddFrameworkToProject(targetUnityTarget,"UTDID.framework",false);
            // pbxProject.AddFrameworkToProject(targetUnityTarget,"UYuMao.framework",false);
            //
            // pbxProject.AddFrameworkToProject(targetUnityTarget,"UMAPM.xcframework",false);
            // pbxProject.AddFrameworkToProject(targetUnityTarget,"UMLink.framework",false);
            
            //[WXApi genExtraUrlByReq:withAppData:]
            //报错 原因缺少 Wxapi genExtraUrlByReq 函数, 
            //-all_load 加载 所有的 静态链接库, 但是这个存在动态链接库的函数重复的问题,编译会报错
            //-force_load 强制 指定加载 静态链接库。
            pbxProject.AddBuildProperty(targetUnityTarget,"OTHER_LDFLAGS","-ObjC -force_load $SRCROOT/Libraries/Plugins/SDK/iOS/WechatSDK/libWeChatSDK.a");
            //pbxProject.AddFrameworkToProject(target,"WechatOpenSDK-XCFramework.xcframework",false);
            
            //Unity Tests
            string targetGuid = pbxProject.TargetGuidByName(PBXProject.GetUnityTestTargetName());
            pbxProject.SetBuildProperty(targetGuid, "ENABLE_BITCODE", "NO");
 
            //Unity Framework
            pbxProject.SetBuildProperty(targetUnityTarget, "ENABLE_BITCODE", "NO");
            pbxProject.SetBuildProperty(targetUnityTarget, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES");
            
            pbxProject.WriteToFile(pbxProjectPath);
            
            //修改 Info.plist 文件
            var plistPath = locationPath + "/Info.plist";
            var plist = new PlistDocument();
            plist.ReadFromFile(plistPath);

            PlistElementDict rootDict = plist.root;
            
            //设置LSApplicationQueriesSchemes(数组)
            PlistElementArray loginChannelsArr;
            loginChannelsArr = rootDict.CreateArray("LSApplicationQueriesSchemes");
            loginChannelsArr.AddString("weixin");
            loginChannelsArr.AddString("weixinULAPI");
            loginChannelsArr.AddString("weixinURLParamsAPI");
            
            //百度地图权限
            rootDict.SetString("NSLocationWhenInUseUsageDescription","前台定位");
            rootDict.SetString("NSLocationAlwaysUsageDescription", "永久定位");
            rootDict.SetString("NSLocationAlwaysAndWhenInUseUsageDescription","永久定位");
            
            //添加 url scheme
            PlistElementArray urlTypes = rootDict.CreateArray("CFBundleURLTypes");
            PlistElementDict wxUrl = urlTypes.AddDict();
            wxUrl.SetString("CFBundleTypeRole","Editor");
            wxUrl.SetString("CFBundleURLName","weixin");
            PlistElementArray wxUrlScheme = wxUrl.CreateArray("CFBundleURLSchemes");
            wxUrlScheme.AddString("wxid");

            PlistElementDict aliPay = urlTypes.AddDict();
            aliPay.SetString("CFBundleTypeRole","Editor");
            aliPay.SetString("CFBundleURLName","alipay");
            PlistElementArray aliUrlScheme = aliPay.CreateArray("CFBundleURLSchemes");
            aliUrlScheme.AddString("hjhaGameAliPay");
            
            plist.WriteToFile(plistPath);

接 苹果SDK 做上架准备

不得不吐槽一下,苹果文档真垃圾,真垃圾,真垃圾

1.沙盒模式的测试账号创建,提示This email address is not available for use as an Apple ID. You may already have an Apple ID associated with this address. Please try again or sign in using your existing Apple ID.
这个账号不是指你当前有的账号,也就是不能输入当前存在的账号,可以随便输入,但不能跟现有的账号重复。它只是测试的

2.接入Apple Pay 一直提示 付费应用程序协议有新版本。但是又没有给同意条款的入口。
这个情况应该是还有别的事务还没有处理,或者别的事务还在审核,要等审核通过,才能进行同意条款

3.接错了SDK, TMD Apple Pay 和 游戏内购不是一个东西。我说怎么好像不对劲, 接好变这样。

在这里插入图片描述

4.Apple 开发者里面的内购文档特别不清晰,并且新版内购文档没有,只有旧版的内购文档,并且打上了弃用的标签。网上能查到的资料都是旧版的内购。我参考了一篇别人的文章,比较详细
https://juejin.cn/post/7049626884765646884

5.总结一下内购步骤
继承 SKPaymentTransactionObserver 协议 实现以下方法

// 订单状态有变化就会执行这个函数
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions API_AVAILABLE(ios(3.0), macos(10.7), watchos(6.2), visionos(1.0)){
    for (SKPaymentTransaction *transacation in transactions) {
        switch (transacation.transactionState) {
            
            case SKPaymentTransactionStatePurchasing:
                //NSLog(@"SKPaymentTransactionStatePurchasing 购买中");
                break;
                
            case SKPaymentTransactionStateDeferred:
                NSLog(@"SKPaymentTransactionStateDeferred 支付待处理");
                break;
                
            case SKPaymentTransactionStatePurchased:
                NSLog(@"SKPaymentTransactionStatePurchased 购买成功");
                //存transactions
                [[SKPaymentQueue defaultQueue] finishTransaction:transacation];
                break;
                
            case SKPaymentTransactionStateFailed:
                //购买失败
                [[SKPaymentQueue defaultQueue] finishTransaction:transacation];
                break;
                
            case SKPaymentTransactionStateRestored:
            	[[SKPaymentQueue defaultQueue] finishTransaction:transacation];
                break;
                
            default:
                NSLog(@"transactionState default");
                break;
        }
    }
}
  • 监听处理
    你的SKPaymentTransactionObserver
    (void)application:(UIApplication * _Nullable)application didFinishLaunchingWithOptions:(NSDictionary * _Nullable)launchOptions;
    中添加监听[[SKPaymentQueue defaultQueue] addTransactionObserver:你的SKPaymentTransactionObserver];
    在程序退出的时候- (void)applicationWillTerminate:(UIApplication *)application;
    中移除监听[[SKPaymentQueue defaultQueue] removeTransactionObserver:你的SKPaymentTransactionObserver];

  • 拉起支付
    SKMutablePayment *payment = [SKMutablePayment paymentWithProductIdentifier:productId];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    这个payment 还可以使用[SKMutablePayment paymentWithProduct:product] 得到。

  • 订单支付成功 和 失败都需要 [[SKPaymentQueue defaultQueue] finishTransaction:transacation] 对订单进行移除。否则重启应用,还是会收到订单的购买成功或者失败的状态。
    订单支付失败直接移除。如果订单支付成功,那么需要客户端获取票据发给服务器进行验证,验证完成后,再对订单进行移除。

  • 票据核销
    订单支付成功后,客户端可以获取到一个票据数据。这个票据可以发送给Apple 服务器进行校验。如果校验成功就给用户加上游戏币,或者开通服务。
    核销请看 第四点中到文章,那篇文章比较详细。

  • 沙盒账号登录。
    沙盒账号不要在手机中的设置里进行登录,因为需要邮箱验证,这个沙盒账号的邮箱一般来说是一个不存在的邮箱,没办法验证。退出当前AppStore 账号。然后在测试购买的时候。会弹出账号登录窗口,这个时候可以登录沙盒账号进行登录。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值