SwiftMatrixSDK 0.16.7

SwiftMatrixSDK 0.16.7

测试已测试
语言语言 Obj-CObjective C
许可 Apache-2.0
发布最新发布2020年8月

Emmanuel ROHEEGiomismailgulekSteve Barre 维护。



 
依赖
AFNetworking~> 4.0.0
GZIP~> 1.2.2
OLMKit~> 3.1.0
Realm~> 4.4.0
libbase58~> 0.1.4
 

Matrix iOS SDK

此开源库允许您构建适用于 Matrix(http://www.matrix.org)的 iOS 应用程序,Matrix 是一个用于互操作即时消息和 VoIP 的开放标准。

此 SDK 通过定义在 http://matrix.org/docs/api/client-server/ 的 Matrix 客户端/服务器 API 实现了一个接口。

在您的应用中使用 SDK

SDK 使用 CocoaPods(《https://cocoapods.org.cn/》)作为库依赖项管理器。为了设置这个

sudo gem install cocoapods
pod setup

将 Matrix SDK 的新版本添加到您的应用项目的最佳方式是为您的 Podfile 添加 MatrixSDK 依赖项

# Obj-C
pod 'MatrixSDK'

# Swift
pod 'SwiftMatrixSDK'

如果您想使用 SDK 的开发版本,则使用以下版本:

# Obj-C pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => 'develop'

# Swift pod 'SwiftMatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => 'develop'

选项

如果你想要启用VoIP,请在你的app Podfile中添加以下容器

pod 'WebRTC'

如果你想要启用端到端加密,请添加

pod 'OLMKit'
pod 'Realm'

概述

快速概述,以下是使用SDK所需要了解的类。

Matrix API 级别

MXRestClient:暴露了Matrix标准中指定的Matrix客户端-服务器API,以便向 homeserver 发送请求。

业务逻辑和数据模型

这些类是高级工具,用于处理来自 homeserver 的响应。它们包含维护一致的聊天室数据的逻辑。

MXSession:此类处理所有来自 homeserver 的数据。它使用 MXRestClient 实例从 homeserver 获取数据,并将其转发到 MXRoom、MXRoomState、MXRoomMember 和 MXUser 对象。
MXRoom:此类提供获取房间数据和与房间(加入、离开等)交互的方法。
MXRoomState:这是在某个时间点房间的状态:其名称、主题、可见性(公开/私有)、成员等。
MXRoomMember:表示房间成员。
MXUser:这是当前用户知晓的用户,但不属于房间上下文。MXSession公开并维护MXUser列表。它提供了用户id、displayname和当前存在状态。

用法

示例应用程序(https://github.com/matrix-org/matrix-ios-console)展示了如何在Matrix之上构建一个聊天应用程序。您可以参考它,玩耍,破解它以理解Matrix SDK的完全集成。本节将回到基础,并提供了基本用例的示例代码。

一个需要导入的文件

Obj-C:

#import <MatrixSDK/MatrixSDK.h>

Swift:

import SwiftMatrixSDK

用例 #1:获取 homeserver 的公共房间

此 API 不需要用户进行身份验证。因此,使用 initWithHomeServer 实例化的 MXRestClient 做这项工作

Obj-C:

MXRestClient *mxRestClient = [[MXRestClient alloc] initWithHomeServer:@"http://matrix.org"];
[mxRestClient publicRooms:^(NSArray *rooms) {

    // rooms is an array of MXPublicRoom objects containing information like room id
    NSLog(@"The public rooms are: %@", rooms);

} failure:^(MXError *error) {
}];

Swift:

let homeServerUrl = URL(string: "http://matrix.org")!
let mxRestClient = MXRestClient(homeServer: homeServerUrl, unrecognizedCertificateHandler: nil)
mxRestClient.publicRooms { response in
    switch response {
    case .success(let rooms):

        // rooms is an array of MXPublicRoom objects containing information like room id
        print("The public rooms are: \(rooms)")

    case .failure: break
    }
}

用例 #2:获取用户已交互的房间

在这里,用户需要进行身份验证。我们将使用 [MXRestClient initWithCredentials]。您通常在用户登录后创建和初始化这两个对象,然后在应用的生命周期内或直到用户注销期间保持它们

Obj-C:

MXCredentials *credentials = [[MXCredentials alloc] initWithHomeServer:@"http://matrix.org"
                                                                userId:@"@your_user_id:matrix.org"
                                                           accessToken:@"your_access_token"];

// Create a matrix client
MXRestClient *mxRestClient = [[MXRestClient alloc] initWithCredentials:credentials];

// Create a matrix session
MXSession *mxSession = [[MXSession alloc] initWithMatrixRestClient:mxRestClient];

// Launch mxSession: it will first make an initial sync with the homeserver
// Then it will listen to new coming events and update its data
[mxSession start:^{

    // mxSession is ready to be used
    // Now we can get all rooms with:
    mxSession.rooms;

} failure:^(NSError *error) {
}];

Swift:

let credentials = MXCredentials(homeServer: "http://matrix.org",
                                userId: "@your_user_id:matrix.org",
                                accessToken: "your_access_token")

// Create a matrix client
let mxRestClient = MXRestClient(credentials: credentials, unrecognizedCertificateHandler: nil)

// Create a matrix session
let mxSession = MXSession(matrixRestClient: mxRestClient)

// Launch mxSession: it will first make an initial sync with the homeserver
mxSession.start { response in
    guard response.isSuccess else { return }

    // mxSession is ready to be used
    // now wer can get all rooms with:
    mxSession.rooms
}

用例 #2(bis):使用永久 MXStore 获取用户已交互的房间

我们使用与上面相同的代码,但添加了一个 MXFileStore,它将负责将用户数据存储在文件系统中。这将避免在每次应用恢复时与 homeserver 进行完全同步。应用将能够快速恢复。此外,它还能够脱机运行,同时在同步 homeserver 时运行

Obj-C:

MXCredentials *credentials = [[MXCredentials alloc] initWithHomeServer:@"http://matrix.org"
                                                                userId:@"@your_user_id:matrix.org"
                                                           accessToken:@"your_access_token"];

// Create a matrix client
MXRestClient *mxRestClient = [[MXRestClient alloc] initWithCredentials:credentials];

// Create a matrix session
MXSession *mxSession = [[MXSession alloc] initWithMatrixRestClient:mxRestClient];

// Make the matrix session open the file store
// This will preload user's messages and other data
MXFileStore *store = [[MXFileStore alloc] init];
[mxSession setStore:store success:^{

    // Launch mxSession: it will sync with the homeserver from the last stored data
    // Then it will listen to new coming events and update its data
    [mxSession start:^{

        // mxSession is ready to be used
        // Now we can get all rooms with:
        mxSession.rooms;

    } failure:^(NSError *error) {
    }];
} failure:^(NSError *error) {
}];

Swift:

let credentials = MXCredentials(homeServer: "http://matrix.org",
                                userId: "@your_user_id:matrix.org",
                                accessToken: "your_access_token")

// Create a matrix client
let mxRestClient = MXRestClient(credentials: credentials, unrecognizedCertificateHandler: nil)

// Create a matrix session
let mxSession = MXSession(matrixRestClient: mxRestClient)

// Make the matrix session open the file store
// This will preload user's messages and other data
let store = MXFileStore()
mxSession.setStore(store) { response in
    guard response.isSuccess else { return }

    // Launch mxSession: it will sync with the homeserver from the last stored data
    // Then it will listen to new coming events and update its data
    mxSession.start { response in
        guard response.isSuccess else { return }

        // mxSession is ready to be used
        // now we can get all rooms with:
        mxSession.rooms()
    }
}

用例 #3:获取房间消息

我们重用了之前创建的 mxSession 实例

Obj-C:

// Retrieve the room from its room id
MXRoom *room = [mxSession room:@"!room_id:matrix.org"];

// Add a listener on events related to this room
[room.liveTimeline listenToEvents:^(MXEvent *event, MXEventDirection direction, MXRoomState *roomState) {

    if (direction == MXTimelineDirectionForwards) {
        // Live/New events come here
    }
    else if (direction == MXTimelineDirectionBackwards) {
        // Events that occurred in the past will come here when requesting pagination.
        // roomState contains the state of the room just before this event occurred.
    }
}];

Swift:

// Retrieve the room from its room id
let room = mxSession.room(withRoomId: "!room_id:matrix.org")

// Add a listener on events related to this room
_ = room?.liveTimeline.listenToEvents { (event, direction, roomState) in
    switch direction {
    case .forwards:
        // Live/New events come here
        break

    case .backwards:
        // Events that occurred in the past will come here when requesting pagination.
        // roomState contains the state of the room just before this event occurred.
        break
    }
}

让我们使用 paginateBackMessages 加载一些房间历史记录

Obj-C:

// Reset the pagination start point to now
[room.liveTimeline resetPagination];

[room.liveTimeline paginate:10 direction:MXTimelineDirectionBackwards onlyFromStore:NO complete:^{

    // At this point, the SDK has finished to enumerate the events to the attached listeners

} failure:^(NSError *error) {
}];

Swift:

// Reset the pagination start point to now
room?.liveTimeline.resetPagination()

room?.liveTimeline.paginate(10, direction: .backwards, onlyFromStore: false) { _ in
    // At this point, the SDK has finished to enumerate the events to the attached listeners
}

用例 #4:向房间发送文本消息

此操作无需MXSession的任何业务逻辑:我们可以直接使用MXRestClient

Obj-C:

[mxRestClient sendTextMessageToRoom:@"the_room_id" text:@"Hello world!" success:^(NSString *event_id) {

    // event_id is for reference
    // If you have registered events listener like in the previous use case, you will get
    // a notification for this event coming down from the homeserver events stream and
    // now handled by MXSession.

} failure:^(NSError *error) {
}];

Swift:

client.sendTextMessage(toRoom: "the_room_id", text: "Hello World!") { (response) in
    if case .success(let eventId) = response {
        // eventId is for reference
        // If you have registered events listener like in the previous use case, you will get
        // a notification for this event coming down from the homeserver events stream and
        // now handled by MXSession.
    }
}

推送通知

在Matrix中, homeserver可以在某些事件出现时向用户发送通知。但在APNS中,只有作为应用开发者的 you 可以发送APNS通知,因为这样做需要你自己的APNS私钥。Matrix因此需要一个独立的服务器,与homeservers解耦,以发送推送通知,因为你不能信任任意的homeservers来处理你的应用的APNS私钥。这个被称作'推送网关'。更多关于Matrix中通知如何工作,请参考http://matrix.org/docs/spec/push_gateway/unstable.html

简单来说,为了你的应用能接收推送通知,你需要设置一个推送网关。这是一个公开可访问的服务器,是针对你特定的iOS应用的设计,它可以接收来自Matrix Homeserver的HTTP POST请求并发送APNS。Matrix提供了一个参考推送网关'sygnal',可以在https://github.com/matrix-org/sygnal找到,附带如何设置的说明。

你还可以编写自己的推送网关。关于HTTP推送通知协议的规范,请参考http://matrix.org/docs/spec/push_gateway/unstable.html。你的推送网关可以监听任何路径上的通知(只要你的应用知道这个路径以便通知homeserver),但Matrix强烈建议URL路径为'/_matrix/push/v1/notify'。

在你的应用中,你首先以正常方式申请APNS(假设iOS 8或更高版本)

UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIRemoteNotificationTypeBadge
                                                                                     |UIRemoteNotificationTypeSound
                                                                                     |UIRemoteNotificationTypeAlert)
                                                                                     categories:nil];
[...]

- (void)application:(UIApplication *)application
        didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    [application registerForRemoteNotifications];
}

当收到这个特定应用实例的APNS令牌时,你将其编码成文本,并用作`pushkey`来调用`setPusherWithPushkey`,以通知homeserver通过你的推送网关的URL发送推送。Matrix建议对APNS令牌进行base 64编码(因为sygnal就是这样使用的)

- (void)application:(UIApplication*)app
  didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
    NSString *b64Token = [self.deviceToken base64EncodedStringWithOptions:0];
    NSDictionary *pushData = @{
        @"url": @"https://example.com/_matrix/push/v1/notify" // your push gateway URL
    };
    NSString *deviceLang = [NSLocale preferredLanguages][0];
    NSString *profileTag = makeProfileTag(); // more about this later
    MXRestClient *restCli = [MatrixSDKHandler sharedHandler].mxRestClient;
    [restCli
        setPusherWithPushkey:b64Token
        kind:@"http"
        appId:@"com.example.supercoolmatrixapp.prod"
        appDisplayName:@"My Super Cool Matrix iOS App"
        deviceDisplayName:[[UIDevice currentDevice] name]
        profileTag:profileTag
        lang:deviceLang
        data:pushData
        success:^{
            // Hooray!
        } failure:^(NSError *error) {
            // Some super awesome error handling goes here
        }
    ];
}

调用`setPusherWithPushkey`时,在你的会话登录的homeserver上创建一个推送器。这将向提供的URL发送HTTP通知,作为`data`参数中的`url`键。

关于这些参数的更多信息,请参见客户端/服务器规范(http://matrix.org/docs/api/client-server/#!/Push32notifications/post_matrix_client_r0_pushers_set)。以下是对其中一些参数的简要说明

appId
该功能有两个目的:首先是为了在 homeserver 上创建您的 pushkeys 所在的命名空间,这意味着您应该使用应用程序特定的唯一标识符:强烈推荐使用反向 DNS 风格的标识符。第二个目的是让您的应用识别 Push Gateway,这样 Push Gateway 就知道在与 APNS 网关通信时使用哪个私钥和证书。因此,根据您的应用程序是否处于生产或沙箱推送模式,您应该使用不同的应用 ID,以便 Push Gateway 可以相应地发送 APNS。Matrix 建议相应地使用'.dev'或'.prod'后缀您的 appId。
profileTag
此标识符用于确定该设备应遵守的推送规则集。有关推送规则的信息,请参阅客户端/服务器推送规范:http://matrix.org/docs/api/client-server/#!/Push32notifications/post_matrix_client_r0_pushers_set 这是该设备将遵守的设备特定推送规则集的标识符。建议自动生成一个16位的字母数字字符串,并在整个应用程序数据生命周期中使用此字符串。更高级的使用方法将允许多个设备共享一组推送规则。

开发

仓库包含一个 Xcode 项目以进行开发。此项目不会构建应用程序,而是构建一个测试套件。有关设置测试环境的信息,请参阅下一部分。

在打开 Matrix SDK Xcode 工作空间之前,您需要构建它。

该项目在 pod 文件中声明了一些第三方库依赖项。您需要运行 CocoaPods 命令下载它们并为 Matrix SDK 工作区设置环境。

$ pod install

然后,打开 MatrixSDK.xcworkspace

测试

SDK Xcode 项目中的测试既包括单元测试也包括集成测试。

出厂时,测试使用“示例 homeservers 联邦”中的某个 homeserver(位于https://:8080)。(https://github.com/matrix-org/synapse#running-a-demo-federation-of-homeservers)。您必须从您的本地 Synapse 文件夹中启动它们。

$ virtualenv env
$ source env/bin/activate
$ demo/start.sh --no-rate-limit

然后,您可以从 Xcode 测试导航器选项卡中运行测试,或选择 MatrixSDKTests 计划并单击“测试”操作。

已知问题

CocoaPods可能在OSX 10.8.x上安装失败,显示“i18n需要Ruby版本≥1.9.3”。这是一个已知问题,类似于https://github.com/CocoaPods/CocoaPods/issues/2458,需要与CocoaPods团队提出。

### 动态框架:架构未定义的符号

如果您使用“MatrixSDK”而不是“SwiftMatrixSDK”,您可能会遇到编译时错误,看起来像这样

Undefined symbols for architecture x86_64:
  "_OBJC_CLASS_$_GAIDictionaryBuilder", referenced from:
      objc-class-ref in MXGoogleAnalytics.o
  "_OBJC_CLASS_$_GAI", referenced from:
      objc-class-ref in MXGoogleAnalytics.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

当以下两个条件都成立时,就会出现这种情况

1. MatrixSDK作为框架编译(即在您的podfile中启用了use_frameworks!设置)2. 您的项目还使用了Google Analytics pod。

根本原因在于MXGoogleAnalytics类识别到Google Analytics pod被添加到您的项目中,并尝试添加其头文件。这种类型的行为在静态库中是允许的,但在动态框架中是不允许的。

最简单的解决方案是切换到“SwiftMatrixSDK”pod,即使您不使用Swift(对于Obj-C项目,这些pod实际上是相同的)。SwiftMatrixSDK排除了MXGoogleAnalytics类。如果您想收集有关初始化时间等的数据分析,可以实现自己的MXAnalyticsDelegate并将其实例设置为MXSDKOptions.sharedInstance。有关更多信息,请参阅MXAnalyticsDelegate.h和MXGoogleAnalytics.h/m。

注册

当前SDK仅管理登录密码类型注册。这种类型的注册不受matrix.org上托管的家服务器接受。出于安全和垃圾邮件的原因,该功能已禁用。因此,目前您无法在此家服务器上使用SDK注册新的账户。但您可以登录现有用户。

如果您运行自己的家服务器,默认启动参数启用了登录密码类型注册,您可以为它注册新用户。

版权 & 许可

版权(c)2014-2016 OpenMarket Ltd

根据Apache License,版本2.0(“许可证”);除非您根据法律规定或书面同意使用此作品,否则不得使用此作品。您可以在LICENSE文件中或从以下位置获得许可证:

https://apache.ac.cn/licenses/LICENSE2.0

除非法律规定或书面同意,否则根据许可证分发的软件按“原样”分发,不提供任何明示或暗示的保证或条件。有关权限和限制的特定语言,请参阅许可证。