C8oSDK iOS
目录
介绍
关于 SDK
这是 Convertigo 的原生 Swift iOS 库
Convertigo 客户端 SDK 是一套用于移动或 Windows 桌面应用程序访问 Convertigo 服务器服务的库。使用 SDK 的应用程序可以轻松访问 Convertigo 服务,例如序列和事务。
客户端SDK将抽象开发者处理通信协议、本地缓存、FullSync离线数据管理、UI线程管理以及远程日志的工作。因此,开发者可以专注于应用构建。
客户端SDK支持:
- Android原生应用,作为一个标准的Gradle依赖
- iOS原生应用,作为一个标准的CocoaPod
- React Native,作为一个NPM包
- Google Angular框架,作为一个TypeScript的NPM包
- Vue.js、ReactJS、AngularJS框架或任何JavaScript项目,作为一个标准的JavaScript NPM包
- Windows桌面或Xamarin应用,作为Nugets或Xamarin组件
当前包是原生iOS SDK。有关其他SDK,请参阅官方Convertigo文档。
关于Convertigo平台
Convertigo移动平台支持原生iOS开发者。通过Convertigo MBaaS SDK,平台带来的服务可供iOS客户端应用使用。SDK提供了一个iOS框架,您可以使用它访问Convertigo服务器的服务,例如
- 连接到后端数据(SQL、NoSQL、REST/SOAP、SAP、- WEB HTML、AS/400、主机)
- 服务器端业务逻辑(协议转换、业务逻辑增强等)
- FullSync技术自动离线复制的数据库
- 安全和访问控制(身份管理器、LDAP、SAML、oAuth)
- 服务器端缓存
- 推送通知(APNs、GCM)
- 审计分析和日志(SQL和Google Analytics)
要求
- Cocoapods >= 1.5.3
- Xcode >= 9.4
安装
创建一个PodFile,使用
use_frameworks!
target 'MyApp' do
pod 'C8oSDK', '2.3.3'
end
然后输入
$ pod install
重启Xcode并打开.xcworkspace
到这儿就完成了!
文档
完整文档可供查阅 此处
初始化 Convertigo 端点
您可以拥有任意数量的 C8o 实例,指向同一个或不同的端点。每个实例都处理自己的会话和设置。我们强烈建议每个应用程序只使用一个 C8o 实例,因为服务器许可可能是根据使用的会话数量确定的。
import C8o
// In swift there is two ways to handle errors :
// We can either choose to don't care about errors using the following syntax (this may produce in case of error an "EXC_BAD_INSTRUCTION")
let c8o : C8o = try! C8o(endpoint: "https://demo.convertigo.net/cems/projects/sampleMobileCtfGallery")
// or we can choose to use do/catch syntax that will allow us to catch errors
do{
let c8o : C8o = try C8o(endpoint: "https://demo.convertigo.net/cems/projects/sampleMobileCtfGallery")
}
catch let e as NSError{
print(e.description
}
// the C8o instance is ready to interact over https with the demo.convertigo.net server, using sampleMobileUsDirectoryDemo as default project.
高级实例设置
端点是获取 C8o 实例的必选设置,但通过 C8oSettings 类还可以进行其他设置。
A C8oSettings 实例应在端点之后传递。设置会被复制到 C8o 实例中,C8oSettings 实例在 C8o 构造函数之后可以修改和重复使用。
C8oSettings 的设置器总是返回其自身的实例,并且可以串联。
C8oSettings 可以从一个现有的 C8oSettings 或 C8o 实例中实例化。
import C8o
// The common way
var c8o : C8o = try! C8o(endpoint: "https://demo.convertigo.net/cems/projects/sampleMobileCtfGallery", c8oSettings: C8oSettings().setDefaultDatabaseName("mydb_fullsync").setTimeout(30000))
// The verbose way
let endpoint : String = "https://demo.convertigo.net/cems/projects/sampleMobileCtfGallery"
let c8oSettings : C8oSettings = C8oSettings()
c8oSettings.setDefaultDatabaseName("mydb_fullsync")
c8oSettings.setTimeout(30000)
c8o = try! C8o(endpoint: endpoint, c8oSettings: c8oSettings)
// customize existing settings
var customSettings : C8oSettings = C8oSettings(c8oSettings: c8oSettings).setTimeout(60000);
// or from a C8o instance
customSettings = C8oSettings(c8oSettings: c8o).setTimeout(60000);
// all settings can be retrieve from a C8o or C8oSettings instance
let timeout : Int = c8o.timeout
调用 Convertigo 可请求项
有了 C8o 实例,您可以调用 Convertigo 序列和事务,或者对您的本地 FullSync 数据库进行查询。您必须指定您想要的返回结果类型:XML 文档或 JSON 对象响应。
返回 JSON
只需使用 c8o.callJson
方法请求 JSON 响应。
import SwiftyJSON
// c8o is a C8o instance
let jObject : JSON = try! c8o.callJson(".getSimpleData").sync()!
// You now have JSON object that you can use in your app!
返回 XML
只需使用 c8o.callXml 方法请求 XML 响应。
import AEXML
// c8o is a C8o instance
let document : AEXMLDocument = try! c8o.callXml(".getSimpleData").sync()!
调用参数
调用方法期望以下语法的请求者字符串
- 对于一笔交易:[项目].connector.transaction
- 对于一批处理:[项目].sequence
项目名称是可选的,也就是说如果未指定,将使用端点中指定的项目。
Convertigo 可请求的对象通常需要键/值参数。键总是字符串,值可以是任何对象,但字符串是标准情况。
这里有一个使用 JSON 的示例,但对于 XML 请求也会有同样的处理。
// the common way with parameters
let JObject : JSON = try! c8o.callJson(".getSimpleData",
parameters:
"firstname", "John",
"lastname", "Do"
)!.sync()!
// the verbose way
var parameters : Dictionary = Dictionary()
parameters["firstname"] = "John"
parameters["lastname"] = "Do"
let JSONObject : JSON = try! c8o.callJson(".getSimpleData", parameters: parameters)!.sync()!
使用线程
你可能注意到了,呼叫方法不会直接返回结果,并且所有示例代码都链接到 .sync()
方法。
这是因为呼叫方法返回一个 C8oPromise
实例。这允许开发人员选择是否想要阻塞当前线程,进行异步请求或通过回调获取响应。.sync()
方法锁定当前线程,并只要结果可用就返回。当然,不应在 UI 线程中使用,因为这会导致 UI 结冻,直到服务器返回数据。您应仅在工作线程中使用 .sync()
方法。
// lock the current thread while the request is done
let JSONObject : JSON = try! c8o.callJson(".getSimpleData")!.sync()!
// the response can be used in this scope
与许多情况一样,锁定当前线程是不推荐的,.then()
方法允许注册一个在工作线程上执行的回调。.thenUI()
方法执行相同操作,但回调将在 UI 线程上执行。这适用于快速更新 UI 小部件。.then()
和 .thenUI()
回调将响应和请求参数作为参数。
// doesn't lock the current thread while the request is done
c8o.callJson(".getSimpleData")?.then({ (response, parameters) -> (C8oPromise?) in
// the jObject is available, the current code is executed in an another working thread
return nil // return nil for a simple call
})
// following lines are executed immediately, before the end of the request.
c8o.callJson(".getSimpleData")?.thenUI({ (response, parameters) -> (C8oPromise?) in
// the jObject is available, the current code is executed in the UI thread
self.simpleLabel.text = response.stringValue
return nil // return nil for a simple call
})
// following lines are executed immediately, before the end of the request.
链接调用
.then()
或 .thenUI()
返回一个 C8oPromise,可用于链接其他承诺方法,例如 .then()
或 .thenUI()
或失败处理程序。
最后的 .then()
或 .thenUI()
必须返回 nil 值。可以混合使用 .then()
和 .thenUI()
,但返回类型必须相同:XML 或 JSON。
c8o.callJson(".getSimpleData", parameters: "callNumber", 1)?.then({ (response, parameters) -> (C8oPromise?) in
// you can do stuff here and return the next C8oPromise instead of deep nested blocks
return c8o.callJson(".getSimpleData", parameters: "callNumber", 2)
})?.thenUI({ (response, parameters) -> (C8oPromise?) in
// you can do stuff here and even modify previous parameters
var parameters : [String : AnyObject]? = nil
parameters!["callNumber"] = 3
parameters!["extraParameter"] = "ok"
return c8o.callJson(".getSimpleData", parameters: parameters)
})?.then({ (response, parameters) -> (C8oPromise?) in
// you can do stuff here and return nil because this is the end of the chain
return nil
})
处理失败
由于许多原因,调用可能会抛出错误:技术故障、网络错误等。
应使用标准的 do/catch 来处理。
这是 .sync()
方法的情况:如果在请求执行过程中发生异常,该方法将抛出原始异常,并可以封装在 C8oException
中。
do{
try c8o.callJson(".getSimpleData")!.sync()
} catch let Exception as NSError{
// process the exception
}
当你使用 .then()
或 .thenUI()
方法时,do/catch 机制无法捕获“未来的”异常或可抛出对象:你必须使用承诺链末尾的 .fail()
或 .failUI()
方法。
每个Promise链允许一个失败的处理器。失败回调提供抛出的对象(如异常)和失败请求的参数。
c8o.callJson(".getSimpleData", parameters: "callNumber", 1)?.then({ (jObject, parameters) -> (C8oPromise?) in
return c8o.callJson(".getSimpleData", parameters: "callNumber", 2)
})?.thenUI({ (response, parameters) -> (C8oPromise?) in
return nil
})?.fail({ (exception, parameters) in
// exception caught from the first or the second CallJson, can be an Exception
// this code runs in a worker thread
//...
})
c8o.callJson(".getSimpleData", parameters: "callNumber", 1)?.then({ (jObject, parameters) -> (C8oPromise?) in
return c8o.callJson(".getSimpleData", parameters: "callNumber", 2)
})?.thenUI({ (jObject, parameters) -> (C8oPromise?) in
return nil
})?.failUI({ (exception, parameters) in
// exception caught from the first or the second CallJson, can be an Exception
// this code runs in a UI thread
//...
})
将设备日志写入Convertigo服务器
基本
应用程序开发人员通常会将日志信息添加到他的代码中。这对于跟踪代码执行、统计或调试很有用。
Convertigo客户端SDK提供了一个API,可以轻松地将日志记录到标准设备日志记录器,通常是在一个专用控制台中。要查看此控制台,必须在计算机上物理连接一个设备。
幸运的是,相同的API也发送日志到Convertigo服务器,并与服务器日志合并。您可以在同一个屏幕、同一个时间线中轻松调试您的设备和服务器代码。设备日志包含元数据,例如设备UUID,可以帮助在服务器上筛选日志。
必须指定日志级别
- 致命:用于关键错误信息
- 错误:用于常见错误信息
- 警告:用于意外的情况
- 信息:用于较高级别的消息
- 调试:用于帮助开发者理解执行过程
- 跟踪:用于帮助开发者跟踪代码
- 要写入日志字符串,请使用C8o实例的C8oLogger实例
do{
try c8o.log.info("hello world!") // the message can be a simple string
}
catch let e as C8oException{
c8o.log.error("bye world...", exceptions: e) // the message can also take an Exception argument
}
if(c8o.log.isDebug){ // check if currents log levels are enough
// enter here only if a log level is 'trace' or 'debug', can prevent unnecessary CPU usage
let msg : String = serializeData() // compute a special string, like a Document serialization
c8o.log.debug(msg)
}
高级
C8oLogger有两个日志级别,一个用于本地日志记录,另一个用于远程日志记录。使用Android SDK,本地日志记录由logcat选项设置。使用.NET SDK,本地日志记录取决于C8oSettings的LogLevelLocal设置。
远程日志级别是由Convertigo服务器日志级别属性控制的:设备输出日志记录器。在失败的情况下,远程日志记录被禁用,并且无法为当前C8o实例重新启用。也可以使用C8oSettings中的LogRemote设置来禁用它,启用时为true(默认),禁用为false。
要监控远程日志记录失败,可以使用C8oSetting注册一个LogOnFail处理器。
Convertigo客户端SDK本身也会记录日志。可以使用C8oSettings中的LogC8o设置将其关闭,启用时为true(默认),禁用为false。
C8oSettings()
.setLogC8o(false) // disable log from the Convertigo Client SDK itself
.setLogRemote(false) // disable remote logging
.setLogLevelLocal(C8oLogLevel.TRACE)
// or
C8oSettings().setLogOnFail { (exception, parameters) -> (Void) in
// the exception contains the cause of the remote logging failure
}
使用本地缓存
有时我们希望在C8o调用和响应中使用本地缓存,目的是
- 减少设备与服务器之间的网络流量,
- 在设备未连接到网络时能够显示数据。
本地缓存功能允许将C8o调用的响应存储在设备本地,使用变量及其值作为缓存键。
要使用本地缓存,向调用添加一个名为 "__localCache" 的参数对和一个 C8oLocalCache 实例。C8oLocalCache 构造函数需要一些参数:
- C8oLocalCache.Priority (SERVER / LOCAL):定义在设备可以访问网络时,是应从本地缓存还是从Convertigo服务器获取响应。当设备没有网络访问时,使用本地缓存响应。
- ttl:定义缓存响应的有效时间,单位为毫秒。如果没有传递值,则有效时间无限。
- enabled:允许在Convertigo可请求中启用或禁用本地缓存,默认值为true。
// return the response if is already know and less than 180 sec else call the server
try! c8o.callJson(".getSimpleData",
parameters: C8oLocalCache.PARAM, C8oLocalCache(priority: C8oLocalCache.Priority.LOCAL, ttl: 180 * 1000)
)!.sync()
// same sample but with parameters, also acting as cache keys
try! c8o.callJson(".getSimpleData",
parameters: "firstname", "John",
"lastname", "Doe",
C8oLocalCache.PARAM, C8oLocalCache(priority: C8oLocalCache.Priority.LOCAL, ttl: 180 * 1000)
)!.sync()
// make a standard network call with the server
// but in case of offline move or network failure
// return the response if is already know and less than 1 hour
try! c8o.callJson(".getSimpleData",
parameters: C8oLocalCache.PARAM, C8oLocalCache(priority: C8oLocalCache.Priority.SERVER, ttl: 3600 * 1000)
)!.sync()
使用完整同步
完整同步使移动应用能够在完全断开连接的情况下处理,同时仍然由后端业务逻辑处理和控制数据。有关完整同步架构的更多详细信息,请参阅演示。
Convertigo客户端SDK提供了按标准Convertigo序列范式获取本地数据的高级访问。这些与标准序列不同之处在于它们有一个fs://前缀。调用这些本地完整同步请求可以将应用的功能扩展到读取、写入、查询和删除从本地数据库中的数据。
- fs://.create:在不存在的情况下创建本地数据库
- fs://.view:从本地数据库查询视图
- fs://.get:从本地数据库读取对象
- fs://.post:将对象写入/更新到本地数据库
- fs://.delete:从本地数据库中删除对象
- fs://.all:从本地数据库中获取所有对象
- fs://.sync:与服务器数据库同步
- fs://.replicate_push:将本地修改推送到数据库服务器
- fs://.replicate_pull:获取所有数据库服务器修改
- fs://.reset:通过从数据库中删除所有数据来重置数据库
- fs://.put_attachment:将附件添加到数据库中的文档
- fs://.get_attachment:从文档中获取附件
fs://:在端点中指定的项目中的特定FullSync连接器的名称。fs://名称是可选的,除非在C8oSetting上使用setDefaultDatabaseName方法指定了默认数据库名称。
应用程序可以有多个数据库。在移动端(Android、iOS和Xamarin基于的)中,它们存储在应用程序的安全存储中。在Windows桌面应用程序中,它们存储在用户AppData/Local文件夹中,没有应用程序隔离。
所有平台都可以指定一个本地数据库前缀,允许同一远程数据库的多个本地数据库副本。使用C8oSetting上的setFullSyncLocalSuffix方法。
c8o.callJson("fs://base.reset")?.then({ (json, parameters) -> (C8oPromise?) in
// json content:
// { "ok": true }
return c8o.callJson("fs://base.post", // creates a new document on "base", with 2 key/value pairs
parameters: "firstname", "John",
"lastname", "Doe"
)
})?.then({ (json, parameters) -> (C8oPromise?) in
// json content:
// {
// "ok": true,
// "id": "6f1b52df",
// "rev": "1-b0620371"
// }
return c8o.callJson("fs://base.get",
parameters: "docid", json["id"].stringValue) // retrieves the complet document from its "docid"
})?.then({ (json, parameters) -> (C8oPromise?) in
// json content:
// {
// "lastname": "Doe",
// "rev": "1-b0620371",
// "firstname": "John",
// "_id": "6f1b52df"
// }
c8o.log.info(json.stringValue) // output the document in the log
return nil
})
全量同步数据库的复制
FullSync能够在不稳定的连接下复制移动端和Convertigo服务器数据库,同时保持数据的一致性。数据可以向上或向下,或双向复制。复制操作也可以是持续的:新文档会立即复制到另一端。
客户端SDK提供了进度事件,通过C8oProgress实例来监控复制进度。
设备在未进行认证之前不能拉取私有文档或推送任何文档。必须在之前建立会话,并且Convertigo服务器必须认证会话(例如使用设置认证用户步骤)。
// Assuming c8o is a C8o instance properly instanciated and initiated as describe above.
c8o.callJson(".login")?.then({ (json, parameters) -> (C8oPromise?) in if(json == "ok"){
// replication_pull can also be sync or replication_push
c8o.callJson("fs://base.replication_pull")?.then({ (json, parameters) -> (C8oPromise?) in // launches a database replication from the server to the device
// json content:
// { "ok": true }
// the documents are retrieved from the server and can be used
return nil
})?.progress({ (progress) in
// this code runs after each progression event
// progress.Total is calculated and grows up then progress.Current increases to the total
c8o.log.info("progress: " + progress.description)
})
}
return nil
})
带有连续标志的全量同步数据库复制
如上所述,复制操作还可以是持续的:新文档会立即复制到另一端。
在整个应用的生命周期中,每次进入复制都会调用进度函数,直到你明确取消这一次。
c8o.callJson("fs://base.replication_pull", "continuous", true)?.then({ (json, parameters) -> (C8oPromise?) in // launches a database replication from the server to the device
// json content:
// { "ok": true }
// the documents are retrieved from the server and can be used
return nil
})?.progress({ (progress) in
// this code runs after each progression event
// progress.Total is calculated and grows up then progress.Current increases to the total
c8o.log.info("progress: " + progress.description)
})
Full Sync FS_LIVE请求
Full Sync可以在数据库被修改时重新执行fs://调用。在FS_LIVE参数后的then或thenUI会在每次数据库更新后重新执行。数据库更新可以是本地修改或远程修改复制的。
这使你能够保持UI与数据库文档的同步。
FS_LIVE参数必须有一个字符串值,即其liveid。liveid允许取消一个FS_LIVE请求。
c8o.callJson("fs://.view",
parameters: "ddoc", "design",
"view", "customers",
C8O.FS_LIVE, "customers")?.thenUI({ (json, parameters) -> (C8oPromise?) in // launches a live view
// will be call now and after each database update
updateCustomersUI(json)
return nil
})?
…
// cancel the previous FS_LIVE request, can be on application page change for example
c8o.cancelLive("customers")
Full Sync更改监听器
Full Sync还可以通知您数据库中是否有任何更改。在FS_LIVE参数后的进度会在每次数据库更新后被触发。更改包含更改的来源和其他属性
- isExternal
- isCurrentRevision
- isConflict
- id
- revisionId
let changeListener = C8oFullSyncChangeListener(handler: {(changes: JSON) -> () in
checkChanges(changes)
})
…
c8o.addFullSyncChangeListener("base", changeListener) // add this listener for the database "base" ; null or "" while use the default database.
…
c8o.removeFullSyncChangeListener("base", changeListener) // remove this listener for the database "base" ; null or "" while use the default database.
构建 c8osdk-ios
请参阅维基页面