iOS实现微信登录
官方的老旧文档必须得重新梳理梳理

由于目前行业的变化,移动端的开发早已没有铮铮日上的景象了,作为iOS和Android的双料开发,这一现象表现得更为明显。目前在社交网络上已经很少人去分享移动开发的文章和开源库了,新出版的书也是寥寥无几。最近新项目需要开发iOS移动端应用,我发现写个应用需要更仔细地了解技术的实现细节,从搜索引擎中抽丝拨茧,才能理清楚实现方法。

今天就总结下一个基础的功能之一,那就是微信登录。如果你碰巧是iOS新手或者在做闲余项目,可以参考下我的记录,少踩一些坑。

准备工作

我默认你是用Swift开发应用,用Cocoapods管理依赖。还需要准备一些基础的信息:

  • 应用的App ID,需要在微信开放平台新建一个移动应用
  • 应用的Universal Link,根据苹果文档配置,配置好后也需要在微信开放平台填写Universal Link

引入微信SDK

首先打开微信的SDK更新日志,可以看到SDK的更新列表,目前最新的版本是2.0.5。目前有几种可选形式:

  • 下载.a静态资源包(5.9MB)
  • 下载.a静态资源包,无支付(5.8MB)
  • 下载XCFramework形式资源包(4.4MB)
  • 下载XCFramework形式资源包,无支付(4.3MB)
  • 通过CocoaPods安装静态库
  • 通过CocoaPods安装XCFramework

刚开始我奇怪的是,通过CocoaPods安装的时候,没有无支付版本。后来下载资源包下来之后,发现大小也没差多少,其实无所谓了。鉴于CocoaPods使用更方便,配置更简单,直接在Podfile中添加语句:

pod 'WechatOpenSDK-XCFramework'

注意CocoaPods仓库还有个微信官方的依赖叫做WechatOpenSDK(微信官方依赖就这两个,辛苦我翻了半天CocoaPods的官方Spec仓库),它仅仅适用于OC语言项目。如果要在Swift语言中调用它,你还需要创建桥接头文件,才可以让Swfit语言识别并使用依赖。

然后再在命令行中执行命令安装依赖:

pod install

如果后续SDK版本有更新,可以通过命令更新:

pod update

至此,你就可以在代码里引入import WechatOpenSDK并使用库中的类了。

配置微信SDK

配置主要是为了方便在App和微信之间来回跳转。

首先需要配置Info.plist中的LSApplicationQueriesSchemes,它是iOS的隐私安全白名单,只有配置了它,才可以通过canOpenURL方法检测某些应用是否安装(注意这只是限制查询,不限制打开)。微信的scheme有3个,需要把它们全部配置进去。

其次需要配置Info.plist中的CFBundleURLTypes,它是告诉系统,App本身能响应哪些scheme。这个是为了方便微信能跳转回来,微信和我们约定的scheme就是开放平台的App ID。从微信跳转回来的时候,微信可能会带回一些额外信息,这个SDK会读取一些信息比如登录信息和支付信息等,这个我们下面会提到。

你可以参考为微信的官方配置文档,其中4.1.3和4.1.4部分的图片说明了在Xcode哪个地方配置。为了更方便你确认自己的配置是否成功,我给你Info.plist会发生的变化,这样方便你在用git的时候做对比:

<!-- 头部 -->
<dict>
    <!-- 其他配置 -->
    <key>LSApplicationQueriesSchemes</key>
    <array>
        <string>weixin</string>
        <string>weixinULAPI</string>
        <string>weixinURLParamsAPI</string>
    </array>
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeRole</key>
            <string>Editor</string>
            <key>CFBundleURLName</key>
            <string>weixin</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>微信开放平台上应用的App ID</string>
            </array>
        </dict>
    </array>
    <!-- 其他配置 -->
</dict>

运行微信SDK

和很多的工具SDK一样,微信的SDK同样需要在AppDelegate中对SDK进行初始化:

// 添加微信SDK日志,根据具体情况添加
WXApi.startLog(by: WXLogLevel.detail) { s in print(s)}
        
// 注册APP信息
WXApi.registerApp(APP_ID, universalLink: UNIVERSAL_LINK)

跳转微信

用户点击你应用里的微信登录之后,可以调用以下方法,就跳到微信了:

func sendWechatLoginRequest() {
    let req = SendAuthReq()
    req.scope = "snsapi_userinfo"
    req.state = "[按需传递]";
    WXApi.send(req)
}

跳回应用

这一步就是比较烧脑了,因为它伴随着iOS历史API的变更,以及App跳转方式的变更。

当微信跳转回来的时候,按照我们之前编程经验来说,应该注册一个监听器来接收微信传递过来的信息。微信SDK定义的这样的类就是WXApiDelegate,它有一个onResp方法用于接收微信返回的响应,我们可以这样实现:

/// 微信跳转回来之后,回调此方法
func onResp(_ resp: BaseResp) {
    guard let authResp = resp as? SendAuthResp else { return }
    if (authResp.errCode == 0) {
        let code = authResp.code
        // 调用接口处理身份信息
    } else {
        // 微信登录失败
    }
}

那么谁来实现这个接口,谁来调用呢?我们一步一步探索。

iOS最早的跨App调用方法,是使用URL Scheme。因为任何App都能处理相同的Scheme,导致安全性降低。所以在iOS 9之后,苹果引入了Universal Link。现在iOS已经到26版本了,微信和SDK都迭代了不知道多少个版本了,是不是就不用考虑URL Scheme的跳转方式了。我搜索了相关的信息,以及询问了ChatGPT,都是建议同时保留,那我们就同时支持吧。

假设AppDelegate实现了WXApiDelegate,可以实现以下方法来处理:

/// iOS 9引入,用它来处理Url Scheme
func application(_ app: UIApplication, open url: URL,
                 options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    return WXApi.handleOpen(url, delegate: self)
}

/// iOS 8引入,处理Unversal Link
func application(_ application: UIApplication,
                 continue userActivity: NSUserActivity,
                 restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) -> Bool {
    return WXApi.handleOpenUniversalLink(userActivity, delegate: self)
}

处理了URL Scheme和Unversal Link的回调之后,应用就能正常处理微信的回调了。你可以观察到上面的方法都传入了delegate,这样onResp方法就能正常被调用到了。

需要额外说明的是,下面两个是已经废弃的方法,微信的文档和搜索引擎上的很多文章都可以看到。我在写代码的时候就非常疑惑,到底哪个方法是处理跳转的,我的头都大了。这下你可以省事儿了:

func application(_ application: UIApplication, handleOpen url: URL) -> Bool {...}
func application(_ application: UIApplication, open url: URL,
                 sourceApplication: String?, annotation: Any) -> Bool {...}

多场景支持

在iOS 13之后,苹果开始支持多场景 App,也就是应用可能有多个窗口,比如说在iPad上,应用是支持分屏的,左右两个屏幕可以是同一个应用窗口,为了处理每个窗口,也就是每个场景的事件,很多方法从AppDelegate移到了SceneDelegate。下面是SceneDelegate中的需要实现的相关代码:

/// 处理通过URL Scheme跳转过来的情况
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    guard let url = URLContexts.first?.url else { return }
    WXApi.handleOpen(url, delegate: self)
}

/// 处理通过Universal Link跳转过来的情况
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    WXApi.handleOpenUniversalLink(userActivity, delegate: self)
}

对于目前的新的App开发场景,最低的iOS支持版本可能都在iOS 13以上了,那么其实只保留SceneDelegate中的代码就行了。AppDelegate中的大片代码就删掉了(除非你主动不支持多场景)。从此你就得到了最佳实践!

相关参考


最后修改于 2025-12-09