Unity iOS接入微信登录--cocoapods集成

官方教程:iOS接入指南 | 微信开放文档

我是用cocoapods集成的,因为手动集成老有下面这个问题,一时解决不了

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[WXApi genExtraUrlByReq:withAppData:]: unrecognized selector sent to class

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[WXApi genExtraUrlByReq:withAppData:]: unrecognized selector sent to class

一、安装cocoapods

1、安装Homebrew

国内源:HomebrewCN: Homebrew 国内安装脚本,快速部署 brew ,国内镜像

这个源真的很棒,安装很快。

安装Homebrew

/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"

2、安装cocoapods

brew install cocoapods

二、接入微信登录

1、下载微信sdk

前往下载基本信息 | 微信开放文档,打开压缩文件

我把三个文件放在Plugins/iOS/文件夹下的同一个文件夹内了

2、编写ObjectiveC代码调用微信api

创建WeChatUnity.mm、WXApiManager.h、WXApiManager.mm这三个文件,文件也放在Plugins/iOS/文件夹下

代码内容如下,参考网上大佬的:

WeChatUnity.mm

// WeChatUnity.mm

#import <Foundation/Foundation.h>
#import "WXApiManager.h"
#import <UIKit/UIKit.h>
#import <WXApi.h>

#define UNITY_CS_API extern "C"

static NSString *mWXAppid = nil;

// 将c字符串const char* 转为 oc字符串NSString
static inline NSString * str_c2ns(const char*s)
{
    if (s)
        return [NSString stringWithUTF8String: s];
    else
        return [NSString stringWithUTF8String: ""];
}

// 初始化
UNITY_CS_API void WeChatInit(const char* appId, const char* universalLink)
{
    NSLog(@"WeChatInit");

    //在register之前打开log, 后续可以根据log排查问题,第一次测试sdk时可以取消注释
    // [WXApi startLogByLevel:WXLogLevelDetail logBlock:^(NSString *log) {
    //     NSLog(@"WeChatSDK: %@", log);
    // }];

    // 向微信注册
	mWXAppid = str_c2ns(appId);
    NSString *link = str_c2ns(universalLink);
    NSLog(@"init: %@   %@", mWXAppid, link);
	[WXApi registerApp:mWXAppid universalLink:link];

    // 调用自检函数,第一次测试sdk时可以取消注释
    // [WXApi checkUniversalLinkReady:^(WXULCheckStep step, WXCheckULStepResult* result) {
    //     NSLog(@"%@, %u, %@, %@", @(step), result.success, result.errorInfo, result.suggestion);
    // }];
}

// WeChatUnity.mm
UNITY_CS_API void WeChatLogin(const char* state)
{
    NSLog(@"WeChatLogin");

    SendAuthReq* req = [[SendAuthReq alloc] init];
    req.scope = @"snsapi_userinfo";;
    req.state = str_c2ns(state);
    [WXApi sendReq:req completion:nil];
    // 此时会拉起微信,授权后会回调WXApiManager的onResp方法
}

WXApiManager.h

// WXApiManager.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "WXApi.h"

// @end
@interface WXApiManager : UIResponder<UIApplicationDelegate, WXApiDelegate>

@property (strong, nonatomic) UIWindow *window;

+ (instancetype)sharedManager;

@end

WXApiManager.mm

#import "WXApiManager.h"

@implementation WXApiManager

// 单例
+(instancetype)sharedManager {
    static dispatch_once_t onceToken;
    static WXApiManager *instance;
    dispatch_once(&onceToken, ^{
        instance = [[WXApiManager alloc] init];
    });
    return instance;
}

// WXApiManager.mm

- (void)onResp:(BaseResp *)resp {
	if ([resp isKindOfClass:[SendAuthResp class]]) {
		NSLog(@"微信授权回调");
		if (resp.errCode == 0) {
            UnitySendMessage("UnityAndroidConnector", "WeChatLoginSuccess", ((SendAuthResp *)resp).code.UTF8String);
		}
		else
		{
			// 失败,回调给Unity
            NSString *stringNumber = [NSString stringWithFormat:@"%d", resp.errCode];
			UnitySendMessage("UnityAndroidConnector", "WeChatLoginFail", stringNumber.UTF8String);
		}
	}
}

- (void)onReq:(BaseReq *)req {
	// TODO 微信回调,从微信端主动发送过来的请求
}

@end

创建xxxAppController.mm文件,我这里叫CustomAppController,也放在Plugins/iOS/文件夹下

CustomAppController.mm,内容如下

// CustomAppController.mm
#import "WXApiManager.h"

#import  "UnityAppController.h"
@interface CustomAppController : UnityAppController
@end

IMPL_APP_CONTROLLER_SUBCLASS (CustomAppController)

@implementation CustomAppController

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    [super application:application didFinishLaunchingWithOptions:launchOptions];
	
    // 可以在这里自动注册微信,也可以在手动调用WeChatUnity.mm的WeChatInit进行注册
    // [WXApi registerApp:@"wx123123123" universalLink:@"https://xxx.com/app/"];
    
    return YES;
}


- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    return  [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]];
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    return [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]];
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler
{
    return [WXApi handleOpenUniversalLink:userActivity delegate:[WXApiManager sharedManager]];
}

@end


3、编写Unity代码调用和处理回调

调用方法如下:

        void iOSInit()
        {
            WeChatInit("wx12312312", "https://www.xxx.com/app/");
        }

        void iOSLogin()
        {
            WeChatLogin("app_wechat");
        }


        [DllImport("__Internal")]
        static extern void WeChatInit(string appId, string universalLink);

        [DllImport("__Internal")]
        static extern void WeChatLogin(string state);

回调处理:UnityAndroidConnector.cs

public class UnityAndroidConnector : MonoSingleton<UnityAndroidConnector>
    {
        
        public void WeChatLoginSuccess(string code)
        {
            // 传给服务器
        }

        public void WeChatLoginFail(string codestr)
        {
            int code = int.Parse(codestr);
            // 错误码处理
        }

    }

WXApiManager.mm中的UnitySendMessage方法里的参数就对应UnityAndroidConnector.cs里的方法。

记得:UnityAndroidConnector.cs需要挂载在名为UnityAndroidConnector的组件上,即组件名和脚本名保持一致,这个名字你也可以取你喜欢的

UnitySendMessage("UnityAndroidConnector", "WeChatLoginSuccess", ((SendAuthResp *)resp).code.UTF8String);

UnitySendMessage("UnityAndroidConnector", "WeChatLoginFail", stringNumber.UTF8String);

三、打包

1、引入External Dependency Manager for Unity

 ​​​​​​​GitHub - googlesamples/unity-jar-resolver: Unity plugin which resolves Android & iOS dependencies and performs version management

打开设置,Assets--External Dependency Manager--iOS Resolver--Settings,设置我这边用的是默认的,然后 Always add the main target to Podfile 这个设置取消勾选(不然会在Build Phases--Link Binary With Libraries里添加上一个Pod_xxxx_framework,打包时会报错,需要手动删除)

2、创建xxxDependencies.xml

在任意Editor文件夹下创建一个xxxDependencies.xml,用于cocoapods打包用,我这里是WechatDependencies.xml

WechatDependencies.xml

<?xml version="1.0" encoding="utf-8"?>
<dependencies>
    <iosPods>
        <iosPod name="WechatOpenSDK-XCFramework"  bitcodeEnabled="true" >  </iosPod>
    </iosPods>
</dependencies>

3、xcode配置

直接用脚本配置xcode配置项,该脚本也需要放在任意Editor文件夹下

using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
#if UNITY_IOS
using UnityEditor.iOS.Xcode;


class iOSBuildTool : IPostprocessBuildWithReport
{
    public int callbackOrder { get { return 0; } }
    public void OnPostprocessBuild(BuildReport report)
    {
        if (report.summary.platform == BuildTarget.iOS)
        {
            string projectPath = report.summary.outputPath + "/Unity-iPhone.xcodeproj/project.pbxproj";

            PBXProject pbxProject = new PBXProject();
            pbxProject.ReadFromFile(projectPath);
            //Disabling Bitcode on all targets
            //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.SetBuildProperty(target, "OTHER_LDFLAGS", "-ObjC -all_load -lstdc++ -lsqlite3");
            // 添加framework
            pbxProject.AddFrameworkToProject(target, "Security.framework", false);
            pbxProject.AddFrameworkToProject(target, "CoreGraphics.framework", false);
            pbxProject.AddFrameworkToProject(target, "WebKit.framework", false);

            //Unity Tests
            string targetGuid = pbxProject.TargetGuidByName(PBXProject.GetUnityTestTargetName());
            pbxProject.SetBuildProperty(targetGuid, "ENABLE_BITCODE", "NO");

            //Unity Framework
            string frameworkTarget = pbxProject.GetUnityFrameworkTargetGuid();
            pbxProject.SetBuildProperty(frameworkTarget, "ENABLE_BITCODE", "NO");
            pbxProject.SetBuildProperty(frameworkTarget, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "NO");


            // 写入
            pbxProject.WriteToFile(projectPath);

            // 修改Info.plist文件
            var plistPath = report.summary.outputPath + "/Info.plist";
            var plist = new PlistDocument();
            plist.ReadFromFile(plistPath);

            PlistElementDict rootDict = plist.root;
            // example of adding a boolean key...

            //设置LSApplicationQueriesSchemes(数组)
            PlistElementArray loginChannelsArr;
            loginChannelsArr = rootDict.CreateArray("LSApplicationQueriesSchemes");
            loginChannelsArr.AddString("weixin");
            loginChannelsArr.AddString("weixinULAPI");
            loginChannelsArr.AddString("weixinURLParamsAPI");

            // 添加 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("wx12312312");

            // 是否加密
            rootDict.SetBoolean("ITSAppUsesNonExemptEncryption", false);
            // 麦克风权限
            rootDict.SetString("NSMicrophoneUsageDescription", "允许访问您的麦克风,以便您能够在xxxx中使用语音功能");


            // 应用修改
            plist.WriteToFile(plistPath);

            //xxx是项目得名称,一定要修改成对应的项目名称
            ProjectCapabilityManager projectCapabilityManager = new ProjectCapabilityManager(projectPath, "Entitlements.entitlements", "Unity-iPhone");
            // 添加关联域名
            projectCapabilityManager.AddAssociatedDomains(new string[] {
                "applinks:www.xxx.com",
               
            });

            // 添加通知
            // projectCapabilityManager.AddPushNotifications(true);

            projectCapabilityManager.WriteToFile();
        }
    }
}
#endif

4、Unity--Build Settings--Build

打包后运行.xcworkspace这个工程,别运行xcodeproj那个工程,然后真机测试。

大致流程应该就这些,有问题就参考一下官方辣鸡教程或者其他大佬的方法。

关于Universal Link的说明

微信开发者后台需要配置Universal Link,一般格式为https://xxx.com/yyy/,xxx.com就是你的域名,yyy就是path

同时需要在你的域名根目录下或者.well-known目录下有一个apple-app-site-association文件,大致内容如下,内容格式为json格式,但文件不带任何后缀名(即你可以先创建一个json文件,保存好后删除文件名里的'.json'后缀)。

{
    "applinks": {
        "apps": [],
        "details": [
        	{
            	"appID": "teamid.bundle_id",
            	"paths": ["/app/*"]
            }
        ]
    }
}

teamid可在apple开发者后台拿到,网上搜一下就知道了;bundle_id就是你Unity项目的包名com.xxx.xxxx;paths里的app就对应上面说的app,后面记得加一个‘*’号。

还和Universal Link有关的就是上面提到的WeChatUnity.mm和CustomAppController.mm里的微信注册,那个universalLink的值就是Universal Link,即https://xxx.com/app/,而xcode配置脚本里的applink则是域名,即www.xxx.com,别搞错了。

在安装了你的app的手机safari浏览器地址输入你的Universal Link加随机码(如https://xxx.com/app/abc),转到这个链接时,顶部应该是能出现打开你的app的下拉窗口的,这就表示你的Universal Link配置正确了。

  • 27
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值