A framework that gives you access to the powerful Apigo cloud platform from your iOS app. For more information about Apigo and its features, see Apigo Website and Apigo Documentations.
Apigo.framework
into the Frameworks
sections in your XCode project.
SystemConfiguration.framework
Security.framework
QuartzCore.framework
CoreLocation.framework
CoreGraphics.framework
CFNetwork.framework
AudioToolbox.framework
libsqlite3.0.tbd
applicationId
and clientKey
Application
class to initialize Apigo SDK
Apigo.initialize(withServer: "APIGO_SERVER_URL",
applicationId: "APIGO_APPLICATION_ID",
clientKey: "APIGO_CLIENT_KEY")
(Optional) You can add some custom setup :
Apigo.+setLogLevel:
before initialize SDK.
APLogLevel
mode : none
, error
, warning
, info
, debug
Everything is done!
Storing data on Apigo is built around the MFObject
. Each MFObject
contains key-value pairs of JSON-compatible data. This data is using schema, which means that you need to specify ahead of time what keys exist on each MFObject
from our Apigo Cloud. Then you can simply set a key-value pairs you want to save, and our backend will store it.
For example, let's say you set a Beacon parameters. A single MFObject
could contain :
{
"isActive":true,
"major":1,
"name":"Beacon One",
"minor":284,
"proximityUUID":"CB10023F-A318-3394-4199-A8730C7C1AEC"
}
Keys must be alphanumeric strings. Values can be NSString
, NSNumber
, NSDate
, NSNumber
, or even NSArray
and NSDictionary
- anything that can be JSON-encoded.
Let’s say you want to save the Beacon described above to the Apigo Cloud. The interface is similar to a NSDictionary
, plus the saveInBackground
method:
let data = MFObject(className: "Beacon")
// set data
data["name"] = "Beacon One"
data["proximityUUID"] = "CB10023F-A318-3394-4199-A8730C7C1AEC"
data["major"] = 1
data["minor"] = 284
data["isActive"] = true
data["timestamp"] = Date()
// execute save data
data.saveInBackground { (succeed, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// data saved, show success message
}
If you need to fetch a data with the latest data that is in the cloud, you can call the fetchInBackground
method like so:
// create data from existing objecId
let data = MFObject(withoutDataWithClassName: "Beacon", objectId: "objectId")
// fetching the data
data.fetchInBackground { (object, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// fetch data succeeded
}
To get the values out of the MFObject
, there’s a getX method for each data type:
Bool isActive = data.object(forKey: "isActive") as Bool
Int major = data.object(forKey: "major") as Int
String name = data.object(forKey: "name") as String
Int minor = data.object(forKey: "minor") as Int
String proximityUUID = data.object(forKey: "proximityUUID") as String
If you don’t know what type of data you’re getting out, you can call object(forKey:)
, but then you probably have to cast it right away anyways.
The three special values have their own accessors:
String objectId = data.objectId
Date updatedAt = data.updatedAt
Date createdAt = data.createdAt
After getting the data, you can update your data that stored in cloud using method saveInBackground
.
var data: MFObject // fetched data
// set data
data["name"] = "Beacon Two"
data["proximityUUID"] = "CB10023F-A318-3394-4199-A8730C7C1AEC"
data["major"] = 2
data["minor"] = 284
data["isActive"] = false
data["timestamp"] = Date()
// execute save data
data.saveInBackground { (succeed, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// data updated, show success message
}
To delete a data from the Apigo Cloud, use method deleteInBackground
:
var data: MFObject
data.deleteInBackground { (succeed, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// data deleted successfully
}
So far we’ve used values with type NSString
and NSNumber
. Apigo also supports float
, NSDate
, and NSNull
.
You can nest NSDictionary
and NSArray
objects to store more structured data within a single MFObject
. Overall, the following types are allowed for each field in your object:
String
int
, double
, long
, or float
boolean
JSONArray
JSONObject
java.util.Date
JSONObject.NULL
Some examples:
Int myNumber = 42
String myString = "the number is \(myNumber)"
let myDate = Date()
let myArray = [AnyObject]()
myArray.append(myString)
myArray.append(myNumber)
let myObject = [String:AnyObject]();
myObject["number"] = myNumber
myObject["string"] = myString
let bigObject = MFObject(className: "BigObject")
bigObject["myNumber"] = myNumber
bigObject["myString"] = myString
bigObject["myDate"] = myDate
bigObject["myArray"] = myArray
bigObject["myObject"] = myObject
bigObject["myNull"] = NSNull.null
bigObject.saveInBackground()
There are many other ways to retrieve data with Apigo Query. You can retrieve many data at once, put conditions on the data you wish to retrieve.
In many cases, there is a condition that need to specify which datas you want to retrieve. The MFQuery
offers different ways to retrieve a list of datas. The general pattern is to create a MFQuery
, put conditions on it, and then retrieve a List of matching MFObject
s using the findObjectsInBackground
method with a MFQueryArrayResultBlock
.
For example, to retrieve Beacon
s data with a name
, use the whereKey:equalTo:
method to constrain the value for a key:
let query = MFQuery(className: "Beacon")
query.whereKey("name", equalTo: "Beacon One")
query.findObjectsInBackground { (beacons, error) in
if let e = error as NSError? {
// exception happen, handle the message
return
}
// found the beacons, show in table
}
There are several ways to put constraints on the datas found by a MFQuery
. You can filter out datas with a particular key-value pair with whereKey:notEqualTo:
:
query.whereKey("name", notEqualTo: "Beacon One")
You can give multiple constraints, and datas will only be in the results if they match all of the constraints. In other words, it’s like an AND of constraints.
query.whereKey("name", notEqualTo: "Beacon One");
query.whereKey("major", greaterThan: 1)
You can limit the number of results with limit
. By default, results are limited to 100, but anything from 1 to 1000 is a valid limit:
query.limit = 20 // limit to at most 20 results
You can skip the first results with skip
. This can be useful for pagination:
query.skip = 10 // skip the first 10 results
For sortable types like numbers and strings, you can control the order in which results are returned:
// Sorts the results in ascending order by the beacon's major
query.orderByAscending("major");
// Sorts the results in descending order by the beacon's minor
query.order(byAscending: "minor")
You can add more sort keys to the query as follows:
// Sorts the results in ascending order by the beacon's major field if the previous sort keys are equal.
query.addAscendingOrder("major")
// Sorts the results in descending order by the beacon's minor field if the previous sort keys are equal.
query.addDescendingOrder("minor")
For sortable types, you can also use comparisons in queries:
// Restricts to major < 123
query.whereKey("major", lessThan: 123)
// Restricts to major <= 123
query.whereKey("major", lessThanOrEqualTo: 123)
// Restricts to major > 123
query.whereKey("major", greaterThan: 123)
// Restricts to major >= 123
query.whereKey("major", greaterThanOrEqualTo: 123)
Use whereKey:hasPrefix:
to restrict to string values that start with a particular string. Similar to a MySQL LIKE operator, this is indexed so it is efficient for large datasets:
// Finds beacon's name that start with 'Beacon'.
let query = MFQuery(className: "Beacon")
query.whereKey("name", hasPrefix: "Beacon")
The above example will match any MFObject
where the value in the name String key starts with “Beacon”. For example, both “Beacon One” and “Beacon Two” will match, but “First Beacon” or “Second Beacon” will not.
Use whereEndsWith
to restrict to string values that end with a particular string.
// Finds beacon's name that end with 'One'.
let query = MFQuery(className: "Beacon")
query.whereKey("name", hasSuffix: "One")
The above example will match any MFObject
where the value in the name
String key ends with “One”. For example, “Beacon One” will match, but “One Beacon” will not.
If you just need to count
how many datas match a query, but you do not need to retrieve all the datas that match, you can use count instead of find
. For example, to count how many beacons have major
greater than 123
:
let query = MFQuery(className: "Beacon")
query.whereKey("major", greaterThan: 123)
query.countObjectsInBackground { (count, error) in
if let e = error as NSError? {
// exception happen, handle the message
return
}
// counting succeeded, show beacons count
}
Apigo provide a specialized bucket User that automatically handles much of the functionality required for user management. With this bucket, you’ll be able to manage user account functionality in your app.
The first thing your app will do is probably ask the user to sign up. The following code illustrates a typical sign up:
// create new instance of User
let user = MFUser()
// set default field
user.username = "user.one"
user.password = "user1234"
user.email = "user.one@apigo.com"
// set custom field
user["dateOfBirth"] = Date()
user["height"] = 177.5
user["weight"] = 78
user["isMarried"] = true
user["myObject"] = [String:AnyObject]()
user["myArray"] = [[String:AnyObject]]()
// execute register user asynchronous
user.signUpInBackground { (succeed, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// register succeeded
}
This call will asynchronously
create a new user in your Apigo App. Before it starts, the call will checks to make sure that the email
are unique. Also, it also securely hashes the password
in the cloud using bcrypt. We never store passwords in plaintext, nor transmit passwords back to the client in plaintext.
If a register isn’t successful, you should read the NSError
that is returned. The most likely case is that the email
has already been taken by another user. You should communicate this to your user clearly, and ask them to try a different email
.
After you allow users to sign up, you need be able to let them log in to their account in the future. To do this you can use several method for handling action in login process.
After you allow users to register, you need be able to let them login to their account in the future. To do this, you can use the class method logInWithUsername
.
MFUser.logInWithUsername(inBackground: "myUsername", password: "myPlainPassword") { (user, error) in
// check if there is an exception happen
if let e = error as NSError?
// handle the exception
return
}
// log in succeeded
}
It would be bothersome if the user had to login every time they open your app. You can avoid this by using the cached current
object.
Whenever you use any signup
or login
methods, the user is cached on disk. You can treat this cache as a session, and automatically assume the user is logged in:
if let user = MFUser.current() {
// user logged in, open main page
} else {
// session not found, open login page
}
You can clear the current user by logging them out:
MFUser.logOutInBackground { (error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// log out succeeded
}
To query for users, you need to use the special user query:
let query = MFUser.query()
query?.whereKey("gender", equalTo: "female")
query?.findObjectsInBackground { (users, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// query succeeded, users found
}
In addition, you can use getObjectWithId
to get a MFUser
by id.
Sender is number that plot by admin for sending message, you can't subscribe number that not in backend list. The number that allowed to subscribe are : FREENUM0, FREENUM1.
number
-> String
, used to store number object id.
price
-> Number
, used to store price of this number (readonly).
active
-> Boolean
, used to store status active this record (readonly).
let sender = APMessageSender()
sender.number = "FREENUM1"
sender.saveInBackground { (succeed, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// sender saved, show success message
}
// saved sender
var sender: APMessageSender
// changing new number
sender.number = "FREENUM0"
sender.saveInBackground { (succeed, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// sender updated, show success message
}
// saved sender
var sender: APMessageSender
sender.deleteInBackground { (succeed, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// sender deleted, show success message
}
let query = APMessageSender.query()
query.findObjectsInBackground { (senders, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// senders found, show in a table
}
Recipient is number that plot by user for receiving message. This module is used to send broadcast, with template, and broadcast with template.
number
-> String
, used to store number of recipient validate min.9 max.15 start with 62.
group
-> String
, used to store group name.
params
-> Object
, used to store params value of template validate json object string.
let recipient = APMessageRecipient()
recipient.number = "6281234567890"
recipient.group = "IT"
recipient.params = [
"kode": "901"
]
recipient.saveInBackground { (succeed, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// recipient saved, show success message
}
// saved sender
var recipient: APMessageRecipient
// changing data
recipient.number = "6281234234234"
recipient.group = "Staff"
recipient.params = [
"kode": "902"
]
recipient.saveInBackground { (succeed, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// recipient updated, show success message
}
// saved recipient
var recipient: APMessageRecipient;
recipient.deleteInBackground { (succeed, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// recipient deleted, show success message
}
Request:
let query = APMessageRecipient.query()
query.findObjectsInBackground { (recipients, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// recipients found, show in a table
}
Template is string content message that can possible to custom value by variable with prefix #
. eg. Hi #name
, please use this code #code
to redeem point.
title
-> String
, used to store of title template.
content
-> String
, used to store template content.
approved
-> Boolean
, approved status of this template (readonly).
let template = APMessageTemplate()
template.content = "Dapatkan diskon belanja s.d 50% dengan menukarkan kode #kode ini."
template.title = "Promo Akhir Tahun"
template.saveInBackground { (succeed, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// template saved, show success message
}
// saved template
var template: APMessageTemplate
template.content = "Dapatkan diskon belanja s.d 70% dengan menukarkan kode kupon berikut #kode."
template.title = "Promo Awal Tahun"
template.saveInBackground { (succeed, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// template updated, show success message
}
var template: APMessageTemplate
template.deleteInBackground { (succeed, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// template deleted, show success message
}
let query = APMessageTemplate.query()
query.findObjectsInBackground { (templates, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// templates found, show in a table
}
History data of sending message (SMS, MMS, and USSD)is collected in this module. User can get all of this data or spesific by Message Type.
All fields are readonly.
transactionId
-> String
, unique id that receive from third party of telco.
sender
-> String
, sender of message.
recipient
-> String
, recipient of message.
content
-> String
, content of message.
msgType
-> String
, type of message : sms, mms, or ussd.
sendTime
-> Date
, time of sending message.
receiveTime
-> Date
, time of receiving message.
sandBox
-> Bool
, type of call this api (sandBox:true --> only save data).
status
-> String
, status of sending message : sending and sent.
let query = APMessageLog.query()
query.findObjectsInBackground { (logs, error) in
// check if there is an exception happen
if let e = error as NSError? {
// handle the exception
return
}
// show logs in a list
}
This module is handling function for sending sms, mms, or ussd with 4 types sending method :
Template
-> This method used to sending message with template refer to templateId in _MessageTemplate.
BroadCast with Template
-> this method used to sending message refer to _MessageRecipient and _MessageTemplate.
sender
-> String
, sender number, refer to data in APMessageSender
.
recipient
-> String
, recipient number.
templateId
-> String
, objectId, refer to data in APMessageTemplate
.
params
-> String
, json object string that replace template variable eg. {"kode":"918"}
.
sandBox
-> Boolean
, default false
, set true
if you want to store data only.
let sender: APMessageSender
let recipient = "628123456789"
let template: APMessageTemplate
let params = [
"kode": "abc123"
]
let send = APMessage(directTemplateWith: sender,
recipient: recipient,
template: template,
parameters: params,
messageType: .sms,
sandbox: false)
send?.sendInBackground({ (log, error) in
if let e = error as NSError? {
// handle exception that happen
return
}
// message sent, show succeed message
})
sender
-> String
, sender number, refer to data in MessageSender
.
group
-> String
, group name, refer to data in MessageRecipient
.
templateId
-> String
, objectId, refer to data in MessageTemplate
.
sandBox
-> Boolean
, default false
, set true
if you want to store data only.
let sender: APMessageSender
let template: APMessageTemplate
let params = [
"kode": "abc123"
]
let send = APMessageBroadcast(templateWith: sender,
template: template,
group: "IT",
messageType: .sms,
sandbox: false)
send?.sendInBackground({ (log, error) in
if let e = error as NSError? {
// handle exception that happen
return
}
// message sent, show succeed message
})
The following is a list of all the error codes that can be returned by the Apigo API - Messaging.
Name | Error Code | Description |
---|---|---|
IllegalSenderNumber |
1001 | illegal sender number. |
MissingSenderNumber |
1002 | missing sender number. |
DontHaveActiveSenderList |
1003 | don't have any active sender list. |
SenderAlreadyExist |
1004 | sender number already exist. |
MissingRecipientNumber |
1005 | missing recipient number. |
IllegalRecipientNumber |
1006 | illegal recipient number. |
InvalidParamsFormat |
1007 | invalid params format. |
ObjectParamsMustBeString |
1008 | object value params must be string. |
MissingContentMessage |
1009 | missing message content. |
OverLimitContent |
1010 | max length of body is 160. |
MissingTemplateId |
1011 | missing templateId. |
InvalidTemplateId |
1012 | invalid template id. |
InactiveTemplate |
1013 | inactive template. |
SensitiveWord |
1014 | message contain sensitive word. |
IllegalNotifyUrl |
1015 | illegal notify url. |
DontHaveActiveGroupList |
1016 | don't have any active group list. |
MissingGroupName |
1017 | missing group name. |
MissingMsgType |
1018 | missing message type. |
InvalidMsgType |
1019 | invalid message type. |
OtherCause |
-1 | custom errors. |