Qwasi 2.1.20

Qwasi 2.1.20

测试测试过
Lang语言 Obj-CObjective C
许可证 MIT
发布最后发布2016年3月

Rob RodriguezQwasi Build维护。



 
依赖
AFNetworking~> 2.6.3
GBDeviceInfo~> 3.5.1
QSwizzle~> 0.2.0
BlocksKit>= 0
 

Qwasi 2.1.20

  • 作者:
  • Rob Rodriguez

Qwasi的ios-library提供了一种方便的方法来访问Qwasi JSON-RPC API。

使用方法

要运行示例项目,克隆仓库,并首先从Example目录运行pod install

需求

  1. XCode 6.1+
  2. Cocoapods

安装

Qwasi可在CocoaPods中获得。要安装它,只需将以下行添加到Podfile中:


pod 'Qwasi', '~>2.1.20'

许可证

Qwasi遵照MIT许可证。查看LICENSE文件以获取更多信息。

Pod依赖

 'AFJSONRPCClient'
 'GBDeviceInfo', '~> 3.1.0'
 'Emitter'
 'QSwizzle', '~> 0.2.0'

库初始化Qwasi

默认单例Qwasi

有一个默认的单例Qwasi对象,最适合大多数用例。

Objective-C

    Qwasi* qwasi = [Qwasi shared];

swift

    let qwasi:Qwasi = Qwasi.shared()

分配一个新的Qwasi

通常不需要创建自己的Qwasi对象,但如果有需要,这是简单的。

Objective-C

    Qwasi* qwasi = [[Qwasi alloc] init];

swift

    var qwasi:Qwasi = Qwasi()

库配置QwasiConfig

默认情况下,任何Qwasi实例都将尝试使用以下描述的默认配置。您可以通过设置配置对象显式设置或更改配置。每次更改配置时,您都需要重新注册设备。

Objective-C

    qwasi.config = [QwasiConfig default];

swift

    qwasi.config = QwasiConfig()

默认配置

默认配置文件是Qwasi.plist。您可以在Xcode项目中创建属性列表并将其添加到您的包中。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>apiUrl</key>
    <string>https://sandbox.qwasi.com/v1</string>
    <key>apiKey</key>
    <string>Your Key</string>
    <key>appId</key>
    <string>Your id</string>
</dict>
</plist>

自定义配置文件

您可以使用以下方法从一个属性列表加载配置:

+ (instancetype)configWithFile:(NSString*)path

示例

Objective-C

    QwasiConfig* config = [QwasiConfig configWithFile: @"myconfig"];
    qwasi.config = config;

swift

    var config:QwasiConfig? = QwasiConfig( file: "filename" )

注意:您不应在路径中包含.plist扩展名

运行时配置

您可以使用以下方法动态创建运行时配置对象:

+ (instancetype)configWithURL:(NSURL*)url withApplication:(NSString*)app withKey:(NSString*)key;

示例

Objective-C

    NSURL* url = [NSURL urlWithString: @"https://sandbox.qwasi.com/v1"];
    QwasiConfig* config = [QwasiConfig configWithURL: url withApplication: @"Your app" withKey: @"Your key"];
    qwasi.config = config;

swift

    var url:NSURL = NSURL( string: "https://sandbox.qwasi.com/v1" )!
    var config:QwasiConfig? = QwasiConfig( URL: url, withApplication: "Your app", withKey: "Your key")
    qwasi.config = config

事件发射器

Qwasi 库使用类似于 nodejs 的发射器来发射事件。您可以通过使用注册方法之一注册监听器来监听这些事件。

- (void)on:(id)event listener:(id)listener;
- (void)once:(id)event listener:(id)listener;
- (void)on:(id)event selector:(SEL)selector target:(__weak id)target;
- (void)once:(id)event selector:(SEL)selector target:(__weak id)target;

早期注册

在设备注册之前注册事件处理程序非常重要。否则可能会出现竞争条件(即事件在处理程序创建之前发射)。

多次注册

多次调用具有相同代码段的注册方法会导致多个注册。例如,在如 viewDidLoad 这样的方法中注册将会导致同一块重复收到事件,可能会使您的代码处理消息两次。这是故意设计的,因为您可能希望在多个代码路径中处理消息。但这可能会导致意想不到的副作用。

Objective-C

- (void) viewDidLoad {

    // This will cause this block to be registered EVERY time viewDidLoad is called
    [qwasi on: @"message" listener: ^(QwasiMessage* message) {
            // This will get called once for everytime viewDidLoad is called, per message
    }]; 
}

swift

override func viewDidLoad() {
    super.viewDidLoad()

    // This will cause this block to be registered EVERY time viewDidLoad is called
    qwasi.on( "message" selector: Selector( "messageHandler:") target: self)
}

移除监听器

您可以通过声明您的块并在稍后移除它来处理这个问题。

Objective-C

// Some where else in code
void (^myOnMessage)(QwasiMessage* message) = ^(QwasiMessage* message) {
    // handle the message
};

- (void) viewDidLoad {
    // Remove any existing blocks   
    [qwasi removeListener: @"message" listener: myOnMessage];
    [qwasi on: @"message" listener: myOnMessage];   
}

swift

//somewhere else
func messageHandler( message: QwasiMessage ){
    // do what you will with the message
}

override func viewDidLoad() {
    super.viewDidLoad()

    // remove any existing selectors
    qwasi.removeListener("message", selector: Selector("messageHandler:"), target: self)
    qwasi.on( "message" selector: Selector( "messageHandler:") target: self)
}

常见事件

处理传入的消息

您可以通过qwasi实例的message事件接收消息。

示例

Objective-C

    [qwasi on: @"message" listener: ^(QwasiMessage* message) {
            // Do as you will with the message
    }]; 

swift

    //declared handler
    qwasi.on( "message" selector: Selector( "onMessage:qwasi:") target: self)

    func onMessage(message: QwasiMessage, qwasi: Qwasi) {
        //handle the message how you will
    }
SDK 事件 - "message"
SDK 错误 - QwasiErrorMessageFetchFailed
API 方法 - N/A

错误处理QwasiError

某些方法将具有一个失败回调参数,但所有方法将通过Qwasi实例发射错误。您可以在实例上注册一个默认的错误处理程序并按需处理错误。

示例

Objective-C

[qwasi on: @"error" listener: ^(NSError* error) {
        // Handle Errors here (see QwasiError.h)
        if (error.domain == kQwasiErrorDomain) {
            switch (error.code) {
                default:
                    break;
            }
        }

        DDLogError(@"%@", error);
    }];

swift

    //setup handler
    qwasi.on("error", selector: Selector( "errorHandler:"), target: self)

    //selector elsewhere
    func errorHandler( error: NSError){
        //Handle Error Here (QwasiError.h for more info)
        if ( error.domain == kQwasiErrorDomain){
            switch( error.code){
                //do further handling here
                default:
                    break
            }
        }

        DDLogError(error.description)
    }

设备注册

设备令牌

与Qwasi互动的每个设备都需要一个唯一的设备令牌。此令牌在调用设备注册时返回。它应被存储以供未来的设备注册调用使用,以确保您可以正确跟踪该设备的活动。registerDevice只需要在每个应用程序启动时调用一次,除非您更改配置。

Qwasi.h中定义了许多registerDevice重载,其中最简单和最有用的是

- (void)registerDevice:(NSString*)deviceToken withUserToken:(NSString*)userToken success:(void(^)(NSString* deviceToken))success;

示例

Objective-C

    // Get our device token from the defaults
    NSString* deviceToken = [[NSUserDefaults standardUserDefaults] valueForKey: DEVICE_TOKEN_KEY];

    [qwasi registerDevice: deviceToken withUserToken: USER_TOKEN success: ^(NSString *deviceToken) {
        // We need to store this for later as this is our unique device identifier
        [[NSUserDefaults standardUserDefaults] setValue: deviceToken forKey: DEVICE_TOKEN_KEY];
    }];

swift

    //Get our device token from the defaults
    let deviceToken: String? = defaults.stringForKey("deviceToken")

    qwasi.registerDevice( deviceToken , withUserToken: "userToken", success: { 
        ( deviceToken: String! ) -> Void in 

        // We need to store this for later as this is our Unique Device Identifier
        NSUserDefaults.standardUserDefaults().setObject( deviceToken, forKey: "deviceToken")
        NSUserDefaults.standardUserDefaults().syncronize()

        //do other registration-sensitive activities
    })
SDK 事件 - "register"
SDK 错误 - QwasiErrorDeviceRegistrationFailed
API 方法 - device.register

用户令牌

用户令牌基本上是您的设备标识符。一些开发者使用他们的客户ID或忠诚度ID号,这允许您使用此令牌从平台上对设备进行操作。这些不必是唯一的,可以用来使用单个用户令牌对设备进行分组。默认为""。

您可以通过deviceRegister调用设置用户令牌,或者稍后通过qwasi对象进行设置。

示例

Objective-C

    qwasi.userToken = @"My User Token";

swift

    qwasi.userToken = "My User Token"

如果设备尚未注册,当调用注册时,用户令牌将被更新,否则将简单地使用 device.set_user_token API 调用。

SDK 事件 - N/A
SDK 错误 - QwasiErrorSetUserTokenFailed
API 方法 - device.set_user_token

注销

注销设备将从 Qwasi 数据库中完全删除记录。这适用于满足应用程序对隐私合规性的需求等情况。除非在这些情况下,否则应注销设备。

如果需要,可以使用以下方法注销设备:

- (void)unregisterDevice:(NSString*)deviceToke success:(void(^)())success failure:(void(^)(NSError* err))failure;
SDK 事件 - N/A
SDK 错误 - QwasiErrorDeviceUnregisterFailed
API 方法 - device.unregister

推送通知

Qwasi 支持推送通知的简化注册。设备注册后,您可以在实例上设置 pushEnabled 或调用方法

- (void)registerForNotifications:(void(^)())success failure:(void(^)(NSError* err))failure;

示例

Objective-C

    qwasi.pushEnabled = YES;

    // if you want notification for when the push registration completed
    // this event can occur more than once in an app life-cycle
    [qwasi once: @"pushRegistered" listener: ^(NSString* pushToken) {
        // do with the token as you will... 
    }];

    // if you just want notification and the pushToken for youself
    // this even will only occur once per app life-cycle
    [qwasi once: @"pushToken" listener: ^(NSString* pushToken) {
        // do with the token as you will... 
    }];

swift

    qwasi.pushEnabled = true

    // If you want notification for when the push registration has completed
    // this event will happen once per app life-cycle
    qwasi.once("pushRegistered", selector: Selector( "pushRegSelector:"), target: self)

    // OR if you would like just notification and the pushToken
    // this will happen once per app life-cycle
    qwasi.once("pushToken", selector: Selector( "pushRegSelector:"), target: self)

    // elsewhere in code...
    func pushRegSelector( pushToken: String! ){
        //do with the push token as you will...
    }

注意pushEnabled 标志是异步设置的,因此如果您需要使用该值,您必须在与示例中的完成事件之一接收到之后进行,因为实际上设置的内部操作存在竞争条件。

SDK 事件 - "pushToken"
SDK 错误 - QwasiErrorPushRegistrationFailed
API 方法 - device.set_push_token

APS 服务器覆盖

开发(调试)构建的应用程序将获取仅在 Apple 的沙盒推送网关上使用的 aps 沙盒推送令牌。同样,生产(发布)构建将默认获取一个生产推送令牌。行为可以通过应用程序配置文件进行覆盖,配置文件中有类似以下内容:

<key>aps-environment</key>
<string>development</string>

不支持编辑此配置文件,且不属于本文件的范畴。

Qwasi 通知管理器将尝试根据 DEBUG 预处理器头检测操作模式。要覆盖此模式,您需要在使用 Qwasi 平台的服务器强制传送通知之前手动设置此标志。

Objective-C

[QwasiNotificationManager shared].sandbox = YES; // or NO to force production

swift

QwasiNotificationManager.shared().sandbox = true // or false to force production

后台获取

如果用户不允许推送通知或设备没有网络访问,某些通知可能会错过。如果您的应用有后台获取权限,即使在推送已禁用的情况下,您也将定期收到通知。库会通过抓取未读消息并创建 UILocalNotification 来模拟推送。

消息轮询

如果您的应用程序不支持后台获取,您可以定期调用

- (void)tryFetchUnreadMessages

将此方法放在您的UIApplicationDelegate中是一个好地方。

示例

Objective-C

- (void)applicationDidBecomeActive:(UIApplication *)application {
    ...
    [qwasi tryFetchUnreadMessages];
}

swift

func applicationDidBecomeActive(application: UIApplication) {
     ...
     qwasi.tryFetchUnreadMessages()
}

此方法不会生成通知。

SDK 事件 - "message"(可选)
SDK 错误 - QwasiErrorMessageFetchFailed
API 方法 - message.poll

基于标签的回调

qwasi 实例将为包含在消息中的标签发出特殊事件,可用于根据特殊标签过滤回调。

示例

Objective-C

    // call this so messages with this tag won't get emitter to the default message
    // hander as well
    [qwasi filterTag: @"myCustomTag"];

    [qwasi on: @"tag#myCustomTag listener: ^(QwasiMessage* message) {
        // handle the message with the tag
    }];

swift

    // call this so messages with this tag won't get emitter to the default message
    // hander as well
    qwasi.filterTag( "myCustomTag")

    qwasi.on("tag#myCustomTag", selector: "selectorName:", target: self)

消息频道

Qwasi AIM 通过频道支持任意消息组。API 简单。

订阅频道

- (void)subscribeToChannel:(NSString*)channel;

示例

Objective-C

    [qwasi subscribeToChannel:@"baseball"];

swift

    qwasi.subscribeToChannel( "baseball")
SDK 事件 - N/A
SDK 错误 - QwasiErrorChannelSubscribeFailed
API 方法 - channel.subscribe

从频道退订

- (void)unsubscribeFromChannel:(NSString*)channel;

示例

Objective-C

    [qwasi unsubscribeFromChannel:@"baseball"];

swift

    qwasi.unsubscribeFromChannel("baseball")
SDK 事件 - N/A
SDK 错误 - QwasiErrorChannelUnsubscribeFailed
API 方法 - channel.unsubscribe

应用程序事件

Qwasi 平台支持在应用程序事件上触发,但必须提供事件。默认情况下,库将发送应用程序状态事件(打开、前台、后台)。您可以发送自定义事件并配置您的 AIM 如您所愿对其作出响应

- (void)postEvent:(NSString*)event withData:(id)data;

示例: Objective-C:

    [qwasi postEvent: @"login" withData: @{ @"username": "bobvila" }];

swift

    qwasi.postEvent( "login", withData: [ "username" : "bobvila"] )

位置

Qwasi SDK 可以提供设备位置并跟踪地理围栏和 iBeacon 事件。地理围栏和 iBeacon 必须通过 AIM 或 API 接口事先配置。

启用位置

位置通过qwasi实例启用或禁用,一旦设备注册成功。

Objective-C

    qwasi.locationEnabled = YES;

swift

    qwasi.locationEnabled = true

位置管理器

只能有一个活动的 QwasiLocationManager,您必须在启用位置之前设置此属性,默认为 foregroundManager。

Objective-C

    // Default foreground manager
    qwasi.locationManager = [QwasiLocationManager foreground];

    // Or the background manager
    qwasi.locationManager = [QwasiLocationManager background];

swift

    qwasi.locationManager = QwasiLocationManager.foregroundManager()

    qwasi.locationManager = QwasiLocationManager.backgroundManager()

注意:一旦在应用的第一次运行中设置了一个位置管理器,您可以更改它,但用户需要访问应用设置页面。您可以从后台(许可型)切换到前台(限制型)而无需更改设置。*

SDK 事件 - 无效
SDK 错误 - QwasiErrorLocationSyncFailed
API 方法 - location.fetch

处理位置事件

类似于消息,位置事件也是通过实例上的发射器进行传递的。

示例

Objective-C

    [qwasi on: @"location" listener: ^(QwasiLocation* location, QwasiLocationState state) {
        switch (location.type) {
            case QwasiLocationTypeCoordinate:
                // This is a normal GPS update
                break;

            case QwasiLocationTypeGeofence:
                if (state == QwasiLocationStateInside) {
                   // inside a geofence
                }
                else {
                   // now outside the geofence
                }
                break;

            case QwasiLocationTypeBeacon:
                if (state == QwasiLocationStateInside) {
                    // hit a beacon
                }
                else {
                    // left the beacon proximty
                }
                break;

            default:
                break;
        }
    }]; 

swift

    //earlier in code
    Qwasi.shared().on("location", selector: "onLocation:state:", target: self)
    ...

    // location selector
    func onLocation(location: QwasiLocation, state: QwasiLocationState) {
        switch (location.type) {
        case QwasiLocationType.Coordinate:
            // This isnormal GPS update
            break;

        case QwasiLocationType.Geofence:
            if (state == QwasiLocationState.Inside) {
                // inside a geofence
            }
            else {
                // now outside a geofence
            }
            break;

        case QwasiLocationType.Beacon:
            if (state == QwasiLocationState.Inside) {
                // hit a beacon
            }
            else {
                // left the beacon proximity
            }

            break;

        default:
            break;
        }
    }
SDK 事件 - "location"
SDK 错误 - 无效
API 方法 - 无效

云数据

Qwasi 支持基于键值的云数据存储系统。这些数据存储为成员或设备特定。键可以使用点分隔符表示的深对象路径。

成员数据

每个设备都由一个成员记录支持。成员记录由一个 user_token 确定,并表示一个聚合记录。使用相同的 user_token 在设备之间提供数据可用性。

设置成员数据

- (void)setMemberValue:(id)value forKey:(NSString*)key
               success:(void(^)(void))success
               failure:(void(^)(NSError* err))failure;

- (void)setMemberValue:(id)value forKey:(NSString*)key;
SDK 事件 - 无效
SDK 错误 - QwasiErrorSetMemberDataFailed
API 方法 - member.set_data

获取成员数据

- (void)memberValueForKey:(NSString*)key
                  success:(void(^)(id value))success
                  failure:(void(^)(NSError* err))failure;
SDK 事件 - 无效
SDK 错误 - QwasiErrorGetMemberDataFailed
API 方法 - member.get_data

示例

Objective-C

[qwasi setMemberValue: @"35"
                forKey: @"age"];

[qwasi memberValueForKey: @"age" 
                      success:^(id value) {

                NSLog(@"%@", value);
            } 
                   failure:^(NSError *err) {
            }];             

swift

qwasi.setMemberValue("35", forKey: "age")

qwasi.setMemberValue("35", forKey: "age", success: { () -> Void in

    //handle success

    }) { (error:NSError!) -> Void in

    //handle failure

}

设备数据

设备数据持久至设备,同时也针对成员特定。因此如果 user_token 发生变化,特定于设备的数据集也会发生变化。这使得多个用户可以共享设备,并拥有各自设备上的数据存储。

设置设备数据

- (void)setDeviceValue:(id)value forKey:(NSString*)key
               success:(void(^)(void))success
               failure:(void(^)(NSError* err))failure;

- (void)setDeviceValue:(id)value forKey:(NSString*)key;
SDK 事件 - 无效
SDK 错误 - QwasiErrorSetDeviceDataFailed
API 方法 - device.set_data

获取设备数据

- (void)deviceValueForKey:(NSString*)key
                  success:(void(^)(id value))success
                  failure:(void(^)(NSError* err))failure;
SDK 事件 - 无效
SDK 错误 - QwasiErrorGetDeviceDataFailed
API 方法 - device.get_data

示例

Objective-C

[qwasi setDeviceValue: @"hotrod99"
                forKey: @"user.displayname"];

[qwasi deviceValueForKey: @"user.displayname" 
                      success:^(id value) {

                NSLog(@"%@", value);
            } 
                   failure:^(NSError *err) {
            }];             

swift

qwasi.setDeviceValue("hotrod99", forKey: "user.displayname")

qwasi.setDeviceValue("hotrod99", forKey: "user.displayname", success: { () -> Void in

    //handle success

    }) { (error:NSError!) -> Void in

    //handle failure
}

发送消息

使用 Qwasi API 和 SDK 可以向其他用户发送消息,这可以促进双向通信或聊天应用。Qwasi 并不明确支持此功能,所以大部分实现留给了开发者。您需要管理将您自己的 userTokens 映射到某些有用的数据,这些数据可以存储在所述的设备记录中。

- (void)sendMessage:(QwasiMessage*)message
        toUserToken:(NSString*)userToken
            success:(void(^)())success
            failure:(void(^)(NSError* err))failure;

- (void)sendMessage:(QwasiMessage*)message
        toUserToken:(NSString*)userToken;
SDK 事件 - N/A
SDK 错误 - QwasiErrorSendMessageFailed
API 方法 - message.send

示例接收者

Objective-C

    // filter out our chat tags
    [qwasi filterTag: @"chatMessage"];

    [qwasi on: @"tag#chatMessage" listener: ^(QwasiMessage* message) {
        // handle the message with the tag
        NSString* displayName = [message.payload: @"from"];
        NSLog(@"Got a message from %@", displayName);
    }];

swift

    //filter out our chat tages

    qwasi.filterTag( "chatMessage")
    qwasi.on("tag#chatMessage", selector: Selector("chatMessageHandler"), target: self)

    ...

    func chatMessageHandler( message: QwasiMessage ){
        let displayName = ["from" : message.payload]

        NSLog("Got a message from \(displayName)");
    }

示例发送者

Objective-C

    QwasiMessage* welcome = [[QwasiMessage alloc] initWithAlert: @"You have a new message" 
                                                   withPayload: @{ @"from": @"myusername" }
                                               withPayloadType: nil 
                                                        withTags: @[@"chatMessage"]];

    [qwasi sendMessage: message toUserToken: @"anotheruser"];

swift

    var welcome:QwasiMessage = QwasiMessage(  alert: "You have a new message", 
                                              withPayload: [ "from": "myUserName"], 
                                              withPayloadType: nil, 
                                              withTags: [ "chatMessage"])

    qwasi.sendMessage( welcome, toUserToken: "anotherUser" )