How to send iOS data to Azure mobile service database? - ios

I'm new to swift and Azure and am trying to send some data from my swift app up to my azure mobile database. I have an app with CoreData working but after fetching my data i'm running into difficulties sending it up to azure. I'm trying to use the insert table method from the azure framework.
I've tried this method:
let client = MSClient(applicationURLString: "https://mymobileapp.azure-mobile.net/", applicationKey: "aAaBbBcCc…")
var client = AppDelegate().client // To reference my constant in AppDelegate.swift
var itemTable:MSTable = client.tableWithName("Item")
var itemToInsert:NSDictionary = ["text":"My Awesome Item 1"]
itemTable.insert(itemToInsert,
completion: {
insertedItem, error in
if error{
println("error: \(error)")
}
else{
println("Success!")
}
}
)
But I'm running into problems with the application key. From what I can gather, the application keys are no longer used in Azure Mobile Apps.
I've also tried the method shown in the Mobile App QuickStart guide for swift but the code seems to be for an older version of swift.
I'm not trying to display a table in my app just upload data to the database. Any help would be appreciated!

I ended up getting it to work. The application key is no longer used in the new Azure Mobile Apps. In addition to deleting the key you have to add a new property, specifically a App Transport Security property, to allow for a connection with an unsecured HTTP site.
let client = MSClient(applicationURLString: "https://mymobileapp.azure-mobile.net/")
var client = AppDelegate().client // To reference my constant in AppDelegate.swift
var itemTable:MSTable = client.tableWithName("Item")
var itemToInsert:NSDictionary = ["text":"My Awesome Item 1"]
itemTable.insert(itemToInsert,
completion: {
insertedItem, error in
if error{
print("error: \(error)")
}
else{
print("Success!")
}
}
)

Related

Connecting to the Secure Content in IOS

I am trying to connect to the portal object with the authenticated user which is cached and used throughout the app session, to provide the app with a view of a portal that is centered around a single user.
When the app is restarted, the credential must be reinstated, or the user must repeat the authentication process.
But every time when I connect it asks for username and password, I actually want to embed that into the code.
Any workarounds?
Below is my code.
self.portal = AGSPortal(url: URL(string: "https://www.arcgis.com")!, loginRequired: false)
self.portal.credential = AGSCredential(user: "theUser", password: "thePassword")
self.portal.load() {[weak self] (error) in
if let error = error {
print(error)
return
}
if self?.portal.loadStatus == AGSLoadStatus.loaded {
let fullName = self?.portal.user?.fullName
print(fullName!)
}
}
You can use AGSCredentialCache's enableAutoSyncToKeychainWithIdentifier:accessGroup:acrossDevices:accessible: to store credentials in the Keychain and when you re-launch the app, it won't prompt again. Please call this function at the start of the application using AGSAuthenticationManager.shared().credentialCache.
Regards,
Nimesh

Problem accessing Azure SQL database table from iOS swift app

I created a demo app that authenticates user from Azure Active Directory and able to perform sync with easy tables. When I connected App Service at Azure Portal with SQL database then fetching a table data in iOS swift app throws 401 error. Below is the code snippet.
let client = MSClient(applicationURLString: "URL String")
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext!
self.store = MSCoreDataStore(managedObjectContext: managedObjectContext)
client.syncContext = MSSyncContext(delegate: nil, dataSource: self.store, callback: nil)
self.table = client.syncTable(withName: "table name")
self.refreshControl?.addTarget(self, action: #selector(ActivityTableViewController.onRefresh(_:)), for: UIControlEvents.valueChanged)
API call (onRefresh call):
self.table!.pull(with: self.table?.query(), queryId: "AllRecords") {
(error) -> Void in DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
// throws 401 error here
}
}
Now I have bypassed the user authentication and in Azure App Service, easy table is working fine and I can access data from mobile app.
I connected SQL database with App Service and created a easy table with same name as I have in SQL database. It created the same schema in easy table as I have in SQL database. Now the problem is that I am not able to fetch data in mobile app from this table. SQL database has entries in table.

Manage users in firebase for multi tenant app

We have a ordering system which end users can order meals from their iOS app. Each iOS app belongs to a brand, each user also belongs to a brand. We put all brand information in one firebase project. The database structure is:
-brands
-- brand_id_1:
-- information
-- brand_id_2:
-- information
-stores
-- store_id_1:
-- brand_id:brand_id_1
-- more information
-- store_id_2:
-- brand_id:brand_id_1
-- more information
-orders
--brand_id_1:
--order_id_1:
--orderinfo
--brand_id_2:
--order_id_4:
--orderinfo
-users
-- user_id_1:
-- brand_id:brand_id_1
-- userinfo
-- user_id_2:
-- brand_id:brand_id_2
-- userinfo
We use Facebook and twitter authentication for sign in each app. However, one firebase project can only assign one Facebook app id. That means if user downloads brand1 app and sign in by Facebook , when he or she downloads brand2 app, the user account will be already created and our users will be confused. We hope each brand has their own user database, but we can still manage all the brands and stores data in one firebase project.
What we want to do is put all brands and stores in a main firebase project, then for each brand just create a firebase project for each iOS app. These firebase projects are just for user login (when sign up success put the uid to main firebase project), and all user orders will be saved to our main firebase project.
Is it possible? or any other better solutions?
Whenever you need an isolated set of users for an app, you will need a new project for that app. You can use multiple databases per project following the instructions in this article (it is for Android, but it's similar for iOS -
you will have to initialize a new Firebase app in the client for each project you want to use).
After several hours of study, I come up with other approach. The idea is:
Use Facebook iOS sdk to sign in from iOS app and get Facebook token.
iOS app sends this token to cloud functions, fetch user profile using Graph api, then create custom token from Facebook uid.
Send this custom token back to iOS app.
iOS app uses this token to sign in to firebase.
iOS code :
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if let token = result.token {
print(token.userID)
print(token.appID)
signInuser(with: token)
}
}
func signInuser(with token:FBSDKAccessToken) {
Alamofire.request("https://xxx.cloudfunctions.net/verifyFacebookUser", method: .post, parameters: ["token":token.tokenString]).responseJSON(completionHandler: { (response) in
switch response.result {
case .success(let data):
if let json = data as? [String:String] {
FIRAuth.auth()?.signIn(withCustomToken: json["token"]!, completion: { (user, err) in
if let error = err {
print(error)
}else {
print(user!.displayName)
print(user!.email)
}
})
}
case .failure( let error):
print(error)
}
})
}
cloud functions:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const graph = require('fbgraph');
var serviceAccount = require("./serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://xxx.firebaseio.com"
});
exports.verifyFacebookUser = functions.https.onRequest((req,res) => {
if (!req.body.token) {
return res.status(400).send('Access Token not found');
}
graph.setAccessToken(req.body.token);
graph.get("me?fields=id,name,email", function(err, result) {
const firebaseUid = "fb:"+result.id;
admin.auth().createUser({
uid:firebaseUid,
displayName:result.name,
email:result.email
}).then(function(userRecord){
console.log(userRecord)
admin.auth().createCustomToken(userRecord.uid)
.then(function(customToken) {
res.send({token:customToken});
})
.catch(function(error) {
console.log("Error creating custom token:", error);
})
});
});
});
With this method, the iOS app of each brand will ask user to agree sign in from Facebook even if he or she already sign in from different brand app. However that means iOS app needs to implement Facebook native sign in process which Firebase SDK already provide.

Offline sync with Azure App Service

I try to upgrade an objective-c project to Swift. I'm using Azure App Service with a .NET backend to store data from my mobile app (iOS) in the cloud. I just downloaded the quickstart for Swift project from the azure portal and followed the steps in the tutorial to enable offline sync functionality. However inserting an item in the table is not working. I am using the following code to store a new item in the backend
var table : MSSyncTable?
...
self.table!.insert(item) {
(result) in
let syncItem = result.0
let error = result.1
if error != nil {
print("Error: " + error!.localizedDescription)
}
...
}
Stepping through the code at runtime revealed that error is nil so everything should be working fine, but I am not getting a new entry in my table storage.
Does anybody have experience with Azure App Service and Swift and can help me with this?
Because you are using the sync table, the actual operations to send and receive data from the server are explicit. These are represented by the pushWithCompletion:error: method on the sync context (for sending data up to the cloud), and the pullWithQuery:query:queryId:completion: method on your MSSyncTable.
Note that push automatically occurs when you pull as well.
I would expect the code to look something like:
var table : MSSyncTable?
...
self.table!.insert(item) { result in
let syncItem = result.0
let error = result.1
if error != nil {
print("Error: " + error!.localizedDescription)
}
table!.pushWithCompletion() { error in
...
}
...
}

google places for iOS empty referrer

I have been working completely fine with google maps sdk and the places api. yesterday my code was running perfectly fine. but woke up this morning, made some modifications then ran into a compiling snowball of issues which seems like an easy fix but have spent a couple hours trying to figure out what is going on. I am trying to develop an iPhone application.
I have gone back, created a "new project" in the developer console
regenerated a new iOS key.
entered the new bundle ID in the info.plist
entered the new api key in the delegate file and within the search parameter of the url.
i am using alamofire and swiftyjson to parse the data
but still get the same issue.
2016-01-28 13:15:55.683 Google Maps SDK for iOS version: 1.11.21919.0
{
"error_message" : "This IP, site or mobile application is not authorized to use this API key. Request received from IP address "myIPAddress", with empty referer",
"results" : [
],
"status" : "REQUEST_DENIED",
"html_attributions" : [
]
}
func downloadRestaurantDetails(completed: DownloadComplete) {
let URL_Search = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?"
let API_iOSKey = "My iOS API Key"
let urlString = "\(URL_Search)location=\(clLatitude),\(clLongitude)&radius=\(searchRadius)&types=\(searchType)&key=\(API_iOSKey)"
let url = NSURL(string: urlString)!
Alamofire.request(.GET,url).responseJSON { (response) -> Void in
if let value = response.result.value {
let json = JSON(value)
print(json)
if let results = json["results"].array {
for result in results {
if let placeIDs = result["place_id"].string {
self.placeIDArray.append(placeIDs)
}
}
}
}
completed()
}
}
You've misconfigured your API key.
First, your issue is with the Google Places API Web Service, which can only be used with Server keys not iOS keys. You're calling the web service (https://maps.googleapis.com/maps/place/...) so iOS keys and bundleID key restrictions aren't going to work here (and are likely to confuse things).
So you need to follow the instructions at https://developers.google.com/places/web-service/get-api-key, and make a Server Key with "Google Places API Web Service" enabled in the Developers Console (not the same as "Google Places API for iOS"). To be useful on phones you probably don't want to set any IP restrictions (and IP restrictions are the only kind possible for Server keys). Use that key in your HTTP requests.
Anything else will get REQUEST_DENIED errors.
This error sounds like you have generated a browser key rather than an iOS key. Try generating an iOS key in the Cloud Console and make sure that your bundle ID is whitelisted.

Resources