MOJi辞書之手动集成Tencent SDK遇到的坑!!!

手动集成的原因

由于腾讯未把Tencent SDK上传到Github中,所以我们不能通过Cocoapods的方式集成,只能通过官方下载其SDK手动集成。

Tencent SDK手动集成步骤

1.访问腾讯开放平台SDK下载界面,找到并下载iOS_SDK_V3.5.1。(目前最新)

2.解压该压缩包,会看到TencentOpenApi(Lite)_3文件夹,里面的两个文件(TencentOpenApi_IOS_Bundle.bundle、TencentOpenAPI.framework)就是我们要集成进行的;

3.将以上两个文件导入到项目中,如图所示:

导入TencentOpenAPI框架

4.项目添加QQ白名单(把以下schemes添加到项目的info.plist,以源码的方式打开即可):

<key>LSApplicationQueriesSchemes</key>
<array>
<string>mqqapi</string>
<string>mqq</string>
<string>mqqOpensdkSSoLogin</string>
<string>mqqconnect</string>
<string>mqqopensdkdataline</string>
<string>mqqopensdkgrouptribeshare</string>
<string>mqqopensdkfriend</string>
<string>mqqopensdkapi</string>
<string>mqqopensdkapiV2</string>
<string>mqqopensdkapiV3</string>
<string>mqqopensdkapiV4</string>
<string>mqzoneopensdk</string>
<string>wtloginmqq</string>
<string>wtloginmqq2</string>
<string>mqqwpa</string>
<string>mqzone</string>
<string>mqzonev2</string>
<string>mqzoneshare</string>
<string>wtloginqzone</string>
<string>mqzonewx</string>
<string>mqzoneopensdkapiV2</string>
<string>mqzoneopensdkapi19</string>
<string>mqzoneopensdkapi</string>
<string>mqqbrowser</string>
<string>mttbrowser</string>
</array>

5.添加URL Type,登录腾讯开放平台,获取已经注册好的应用ID,来注册URL Schemes,为tencent+APP ID

6.在腾讯开放平台验证Universal Link。(举例:https://m.mojidict.com/qq_conn/APPID,这一步很重要,涉及到跳转回第三方APP事件)

7.导入依赖框架:

Foundation.framework
UIKit.framework
libc++.tbd
libsqlite3.tbd
Security.framework
libz.tbd
libiconv.tbd
CoreTelephony.framework
CoreGraphics.framework
SystemConfiguration.framework
libz.1.1.3.tbd

8.最后,编译并运行项目,Xcode未报错。So easy的感觉,看似集成成功了!😒

但是…

当导入以下框架并初始化SDK时,

#import <TencentOpenAPI/TencentOAuth.h>
#import <TencentOpenAPI/QQApiInterface.h>


[[TencentOAuth alloc] initWithAppId:MOJiQQAppID andUniversalLink:MOJiQQAppUniversalLink delegate:self];

报错如图所示:

错误1
错误2
错误3

网上查了各种资料都不好使!!!!真的,什么都查过了。试了,还是无解!

突然想到腾讯技术客服…要不问问???

我TM放弃了!!

腾讯没有客服啊…

后面尝试运行官方提供的demo,编译是可以通过的。但是为什么我这里创建的项目就不好使了呢??

一度怀疑人生…

此时经过一番折腾…

然后直盯盯地看着这些错误警告,不知怎滴,突然发现:

上面几张图中,其中错误1、错误3,这两张图,反馈的错误是不能构建模块TencentOpenApi,奇怪了,为什么腾讯的SDK开放给我们的头文件,会有如下导入操作:

#import "sdkdef.h"
#import "QQApiInterfaceObject.h"


注意,我们在自定义框架的时候,都会有这么一段话:

// In this header, you should import all the public headers of your framework using statements like #import <XXX/PublicHeader.h>

然后给外部使用的头文件中,也需要以这这种方式导入头文件,这时候找到对应的头文件,手动分别修改为:

#import <TencentOpenAPI/sdkdef.h>
#import <TencentOpenAPI/QQApiInterfaceObject.h>

修改后图示:

把#import “sdkdef.h”改为#import <TencentOpenAPI/sdkdef.h>
把#import “QQApiInterfaceObject.h”改为#import <TencentOpenAPI/QQApiInterfaceObject.h>

继续步骤8…

9.再次编译运行项目,成功!!!(没办法,只能手动在框架里面修改了)



总结:

1.腾讯的SDK文档老旧,很多操作步骤都是多余的,不建议大家看,直接看这里即可;
2.腾讯做的框架,很垃圾!!没严格按规范编写(仅框架导入头文件这一问题就坑了不少人);
3.项目尽可能严格按照规范来,每次都要Code Review,毕竟我们做的会是一个系统级别的项目;
4.由于一直认为腾讯的产品都是很牛逼,所以一开始就没从Tencent SDK上找原因,当时就一直在查看Xcode或者项目哪里配置出问题了。(中间倒腾了好几回)

所以说,要有敢于怀疑的精神。

MOJi辞書之自定义小组件

实现背景

1.有用户反馈,说目前的小组件背景图不好看,是否可以自定义;
2.让用户选择自己感兴趣的单词库,兴趣是最好的老师。

可自定义的类型

1.选择背景(ImageCrop)
2.选择词库(FolderPicker)

数据的刷新方式

1.小组件自身按约定的时间周期进行刷新;
2.主项目控制小组件刷新;

以下主要讲解”主项目是怎么控制小组件刷新的?”

原理:以桥接的方式,通过OC项目使用Swift的WidgetKit框架,并调用其内部的WidgetCenter.shared.reloadAllTimelines()方法即可。

开始表演:

1.创建一个Swift文件,我们可定义为WidgetKitManager.swift;这时候会弹出一个创建桥接文件的提示,点创建即可。

2.然后把相应的代码实现添加到该Swift文件中,代码段如下:

import WidgetKit

@objc
@available(iOS 14.0, *)
open class WidgetKitManager: NSObject {

    @objc
    static let `default` = WidgetKitManager()
    @objc
    open class var shared: WidgetKitManager {
        get {
            return self.default
        }
    }
    
    /// MARK: 刷新所有小组件
    @objc
    public func reloadAllTimelines() {
       #if arch(arm64) || arch(i386) || arch(x86_64)
       
       WidgetCenter.shared.reloadAllTimelines()
       
       #endif
    }

    /// MARK: 刷新某个小组件(kind: 小组件Configuration 中的kind)
    @objc
    public func reloadTimelines(kind: String?) {
        #if arch(arm64) || arch(i386) || arch(x86_64)
       
        if kind != nil {
            WidgetCenter.shared.reloadTimelines(ofKind: kind!)
        } else {
            WidgetCenter.shared.reloadAllTimelines()
        }
        
        #endif
    }
}

3.然后对主项目进行编译运行,然后报错,信息如下:

<unknown>0: error: using bridging headers with module interfaces is unsupported. Command CompileSwiftSources failed with a nonzero exit code

感觉不对劲,因为是按照网上大部分网友的方法操作的,然后一直卡在这里。。

后面细查了下,有网友建议:在Xcode的Build Settings中找到Build Libraries for Distribution,并设置为NO即可解决。

然后我对其进行了尝试,果真编译通过可运行。突然觉得很爽,问题搞定了!

但是!!

Build Libraries for Distribution在我们发包的时候是有要求的,必须设置为YES。坑爹,该网友的方法不好使。那么怎么办?

继续找…

继续查…

还是没找到答案!!

什么Stack Overflow、什么Google,百度就算了,但连苹果开发者论坛,也是只有人问但没有人给出最佳的答案。

突然灵光一闪!⚡️⚡️⚡️

发现:
我们有好几个框架是用Swift写的,然而他们在编译运行的时候不会报错。(如:BackendConfigRawSwift.xcframework,又如MOJiWordTransformer.xcframework,该框架直接用到主项目中,而且编译运行都不会报错)

这下明白,使用Swift文件与主项目配置的Build Libraries for Distribution = YES时会有冲突(编译出错)。为解决这个冲突,需要把Swift相关实现统一封装成一个库文件(这里我们统一定义为MOJiSwiftKitManager)。

好了,明白其中道理之后,开始进行MOJiSwiftKitManager框架的实现;(这里框架实现略过)

从上面的步骤3,继续往下走…

4.主项目集成MOJiSwiftKitManager框架

5.编译主项目并运行成功!

6.这个时候我们需要一个桥接头文件,对里面的swift文件进行引用,我们创建MOJiDict-Bridging-Header.h(由于已经提示过一次桥接文件创建的弹窗,所以下次再创建Swift文件是不会提示创建了,只能手动创建桥接头文件),头文件内容主要是引用的作用,代码段如下:

@import MOJiSwiftKitManager;

目前,来到这一步,已经接近尾声…

7.最后,我们在需要使用WidgetKit的刷新方法的地方#import "MOJiDict-Bridging-Header.h",并调用[WidgetKitManager.shared reloadAllTimelines];

大功告成!!!


其他注意事项

1.WidgetKit只支持iOS 14+,所以主项目在使用时需做系统版本判断;
2.发包时确保Build Libraries for Distributions为YES;
3.为减少OC项目使用Swift或Swift项目使用OC带来的冲突,尽可能统一框架使用;