How to send messages notifications in iOS? - ios

I am searching for an hour for a way to do that(without Parse because it's going down this month).
I am trying to do in the app that one user can send push notification message to another specific user.
What are the options to implement that?(please be specific)
Thanks.

What you're looking for is not typically recommended, as it can very easily become problematic. Techincally, users should not be able to send direct push notifications to other users. All notifications should be handled through a central system that wouldn't be accessible to your individual users. However, if you feel that you'd still like to make this work, read on.
I have a mechanism like this in one of my apps, using FCM. Here's the function (with some modifications to take out my specific information) that I use to send messages from one user to another:
func push(message: String, toUser: String) {
var token: String?
for person in self.users {
if toUser == person.username && person.firebaseToken != nil {
token = person.firebaseToken
}
}
if token != nil {
var request = URLRequest(url: URL(string: "https://fcm.googleapis.com/fcm/send")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("key=[your FCM Server Key]", forHTTPHeaderField: "Authorization")
let json = [
"to" : token!,
"priority" : "high",
"notification" : [
"body" : message
]
] as [String : Any]
do {
let jsonData = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("Error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
// check for http errors
print("Status Code should be 200, but is \(httpStatus.statusCode)")
print("Response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
}
task.resume()
}
catch {
print(error)
}
}
}
I keep this method in my appDelegate, and call it whenever necessary. Basically, every user in my app has a Firebase messaging token assigned to them, and it's just another property of each user. You can get a user's FCM token with this call:
let token = FIRInstanceID.instanceID().token()
Usually, the token can be retrieved and saved when a user first creates an account. The token will remain the same as long as the user uses the same device.
Again, this can be very dangerous if it is implemented without proper security measures to prevent your users from having total control over sending push notifications.

I am not sure about this.
Although the status code is 200, I can't see any notification.
This is the return value.
{
\"multicast_id\":6666941437973455953,
\"success\":1,
\"failure\":0,
\"canonical_ids\":0,
\"results\":[{\"message_id\":\"0:1490256129594240%03b6b50f03b6b50f\"}]
}

Related

How to fetch specific response from api response and use it with deep linking swift 5

I'm Receiving Response from api using post method like this
'Success{
shortlink = pAHJt7;
status = 200;
} '
I want to use only shortlink with my url to share using deep linking concept.
Here is my code of post method in which I'm getting response from api
func postRequest(latitude:Double,longitude:Double) {
guard let url = URL(string: "http://i.Mallangtech.com/api/Url") else{
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/Json", forHTTPHeaderField: "Content-Type")
let body:[String: AnyHashable] = [
"status": 200,
"shortlink":"okko"]
request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: .fragmentsAllowed)
//hiting api
let task = URLSession.shared.dataTask(with: request) { data, _, Error in
guard let data = data, Error == nil else {
return
}
do{
let response = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print("Success\(response)")
}
catch{
print (error)
}
}
task.resume()
}
```
Lets divide this feature into 4 steps.
Getting Response from API
Sharing the deep link to user.
If user clicks, open the screen
Load the screen with given url.
You have already done the step 1.
For step 2, You can use UIActivityViewController. You can refer this for its implementation.
For step 3 and 4, You need to configure for deep link and handle it inside SceneDelegate. Refer this and you can launch a view controller from SceneDelegate with required params.

Refresh Bearer Token and resume current API

I need to resume my WebService if my bearer token expire by http code 401 ,
below is my code.
When a 401 error occurs that means the Access Token has expired and I need to send a Refresh Token over to my server to obtain a new Access Token.
After getting a new Access Token I need to redo the previous request that got the 401 error.
Suppose I hit webservice1 and its give 401 http code , then new bearer token request will generate and the same API resume to work. How can I do it ?
import UIKit
import CryptoKit
class SharedWebService: NSObject {
static let sharedApiInstance = SharedWebService()
func generalApiMethod (parameter : NSDictionary ,completion: #escaping ((NSMutableArray?) -> Void))
{
var dashboarddata : NSMutableArray = NSMutableArray()
let urlString = String(format:"URL OF API HERE")
let url = URL(string: urlString)
guard let requestUrl = url else { fatalError() }
var request = URLRequest(url: requestUrl)
request.timeoutInterval = 60
let bearerToken = "current bearer token"
request.setValue(bearerToken, forHTTPHeaderField: "Authorization")
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Accept")
URLSession.shared.dataTask(with: request) {
(data, response, error) in
if let httpResponse = response as? HTTPURLResponse {
print(httpResponse.statusCode)
if httpResponse.statusCode == 401
{
// Refresh bearerToken get here
let bearerToken = self.getBearerTokenDevice() //fetch api to get new bearer token
return
}
}
guard error == nil else {
print(error!.localizedDescription);
DispatchQueue.main.async{
completion(dashboarddata)
}
return
}
guard let jsonData = data else { print("Empty data"); return }
if String(data: jsonData, encoding: String.Encoding.utf8) != nil
{
do {
let responseJSON = try? JSONSerialization.jsonObject(with: jsonData, options: [])
if let responseJSON = responseJSON as? [String: Any] {
//Success case do here reponse return
completion(dashboarddata)
}
}
}
}.resume()
}
func getBearerTokenDevice()-> String
{
//how to handle it
return "New bearer token from api fetch"
}
}
work arround is,
Always call Api at splah which fetches Bearer token from server, it will refresh the token every time user opens the app,
2.1 make Api call Queue to process Api calls (Use generics here)
2.2 if api is successfull, Ok. if not than call a special Api call yo get the token,
2.3 if after fetching the token, get last api from Api Queue and call it..
its just an idea, how i think, i think it will be done, might be different in your case
https://stevenpcurtis.medium.com/use-operationqueue-to-chain-api-calls-in-swift-71eefd6891ef
here is guide to make Api call chain

How to pass bearer token to make Yelp API call with URLSessoin

U P D A T E D... The function with what works!
I would like to incorporate the yelp api into an app but can't successfully pass my authorization token on the URL string. Do I need to do something to connect the URLRequest to the URLSessoin call and its not using the header? Maybe the key value pairs is wrong? The below function returns:
error = {
code = "TOKEN_MISSING";
description = "An access token must be supplied in order to use this endpoint.";
};
I was able to use postman to get the yelp API call working, but only by clicking the "Header" section on postman and putting in Bearer and then my yelp key. I googled around a bit and found some links that indicate that you can add a header to the URLSession that I assume would work the way postman does but I haven't been able to get it to work.
I know there are some githubs with yelp API repos but I am trying to not install a large set of code that I don't understand into my app, when all I want is the JSON that I can see is coming through on postman. Can anyone help me understand how I would edit code similar to the Here example below so that I can get the Authorization/Bearer that yelp requires?
func getYelp() {
let appSecret = "Bearer <YELP APIKEY>"
let link = "https://api.yelp.com/v3/businesses/search?latitude=37.786882&longitude=-122.399972"
if let url = URL(string: link) {
// Set headers
var request = URLRequest(url: url)
request.setValue("Accept-Language", forHTTPHeaderField: "en-us")
request.setValue(appSecret, forHTTPHeaderField: "Authorization")
print("Attempting to get places around location from Yelp")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil {
print(error!)
} else {
if let urlContent = data {
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject // Added "as anyObject" to fix syntax error in Xcode 8 Beta 6
print("Printing all JSON/n/n//n--------------------------")
print(jsonResult)
print("Printing from results/n/n//n--------------------------")
if let description = ((jsonResult["search"] as? NSDictionary)?["context"] as? NSDictionary)?["href"] as? String {
} else {
print("JSON pull failed/n/n//n--------------------------")
}
} catch {
print("JSON Processing Failed/n/n//n--------------------------")
}
}
}
}
task.resume()
} else {
resultLabel.text = "Couldn't get results from Here"
}
}
You're mixing up between the headers and the url, you need to set your headers correctly
if let url = URL(string: "https://places.cit.api.here.com/places/v1/discover/around?at=37.776169%2C-122.421267&app_id=\(app_id)&app_code=\(app_code)") {
var request = URLRequest(url: url)
// Set headers
request.setValue("Accept-Language", forHTTPHeaderField: "en-us")
request.setValue("Authorization", forHTTPHeaderField: "Bearer " + token // Token here)
print("Attempting to get places around location")
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
// ...
Lets say you have an api with "https://google.com" (this is just an example with fake keys)
and an api key that is "ApiKey: 92927839238293d92d98d98d92".
You would then take this information and do this.
let uri = URL(string:"https://google.com")
if let unwrappedURL = uri {
var request = URLRequest(url: unwrappedURL)request.addValue("92927839238293d92d98d98d92", forHTTPHeaderField: "ApiKey")
let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
// you should put in error handling code, too
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
// HERE'S WHERE YOUR DATA IS
print(json)
} catch {
print(error.localizedDescription)
}
}
}
dataTask.resume()
}
Please remember that you would replace the google.com with your GET address and the APIKey header with your own api key values.
Also, this will print out all the JSON like in PostMan.
If this works for you, then I also have a link on accessing the JSON Objects.

how to handle Alamofire request when network speed is slow or server is down?

I am new to the Alamofire which I am using to make a request to rest api.
Now while making request there can be two issues and I want to know how to handle those issues using Alamofire.
1) What if user have submit data and Internet is slow and it takes longer to get response from server. In such case how one should insure that whether a request is successful or not. Or we can show some message to user that Internet is slow so he can wait for long response.
2) What if internet speed is ok but the server is down or it is taking longer to send a response how should we handle these situations in our application. And maintain integrity of data.
Following is an example of how I am using Alamofire to make request.
static func getUserListFromServer(completion: #escaping(Bool,[Users]?,String?)->() ){
Alamofire.request(APPURL.getFeedbackUserList, method: .get, parameters: nil, encoding: URLEncoding.queryString, headers: nil).responseJSON { (responseJson) in
responseJson.result.ifSuccess {
do {
// Decode data to object
let jsonDecoder = JSONDecoder()
let root = try jsonDecoder.decode(Root.self, from: responseJson.data!)
if let users = root.users{
completion(true,users,nil)
}else{
completion(false,nil,"No users found.")
}
}
catch let err {
print(err.localizedDescription)
completion(false,nil,err.localizedDescription)
}
}
responseJson.result.ifFailure {
completion(false,nil,responseJson.result.error?.localizedDescription)
}
}
}
You're actually implementing alamofire correctly I would already be about the connection and server problem if network speed is slow. Try using a different endpoint from a different server to test the speed.If its faster then the problem is on your server. Since your implementation is correct then definitely it is server problem. alamofire has nothing to do on handling the issue if the problem is on the server or connection.
You can increase timeout for slow response API calls.
static func getUserListFromServer(completion: #escaping(Bool,[Users]?,String?)->() ){
let request = NSMutableURLRequest(url: APPURL.getFeedbackUserList)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.timeoutInterval = 10 // change time out according to your need
let values = ["key": "value"]
request.httpBody = try! JSONSerialization.data(withJSONObject: values, options: [])
Alamofire.request(request as! URLRequestConvertible).responseJSON { (responseJson) in
responseJson.result.ifSuccess {
do {
// Decode data to object
let jsonDecoder = JSONDecoder()
let root = try jsonDecoder.decode(Root.self, from: responseJson.data!)
if let users = root.users{
completion(true,users,nil)
}else{
completion(false,nil,"No users found.")
}
}
catch let err {
print(err.localizedDescription)
completion(false,nil,err.localizedDescription)
}
}
responseJson.result.ifFailure {
completion(false,nil,responseJson.result.error?.localizedDescription)
}
}
}

How to make POST Request to Server for OTP Verification?

I'm having a scenario in which
1) I'm registering my mobile number using post request.
2) On successfull registration will get OTP on my registered mobile number.
3) After receiving the OTP, I have to verify this OTP on the server.
4) And then server will send me the pin on my registered mobile number,using this pin will able to login my app.
Now coming to the issue after on successfull registration I received an OTP but how to verify this otp and get the pin on my number?.
I have used below code for this. 0123456789 is my registered mobile number and 3588 is the code have received on successfull registration.
#IBAction func verifyotp(_ sender: Any) {
var request = URLRequest(url: URL(string: "myurl/verifyotp?mobileno=0123456789&otp=3588")!)
request.httpMethod = "POST"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
DispatchQueue.main.async {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
self.present(vc, animated: true)
}
}
task.resume()
}
But somehow It didnt match the scenario and m receiving the response like:
Optional("{\"Success\":\"No Active account found.\"}")
Looking for a help.Thanks in advance.

Resources