Push-уведомления IOS между устройствами - GCDAsyncSocket

Привет коллеги программисты,

Я пытаюсь разрешить пользователям отправлять push-уведомления другим пользователям (например, отправлять запрос на добавление в друзья и т. Д.).

Конечной целью здесь является то, чтобы мое приложение для iOS непрерывно прослушивало определенное имя хоста / URL-адрес порта после того, как пользователь вошел в свою учетную запись (или загрузил определенный вид). Мой стек - это экспресс-сервер, взаимодействующий с MongoDB.

Допустим, что пользователь с {account_id} вошел в систему, путь к его учетной записи будет: " http://72.89.157.153:3000/accounts/{account_id}

Я хотел бы, чтобы мое приложение прослушивало любые запросы, отправленные на этот URL. Я использую библиотеки GCDAsyncSocket, чтобы помочь с причиной. Однако, когда я подключаюсь к http://72.89.157.153:3000/ для целей тестирования, функция делегата не вызывается. Я видел много людей с этой же проблемой, но я не могу найти решение, которое я прочитал, чтобы справиться с ситуацией.

Код:

SocketConnection.h

#ifndef SocketConnection_h
#define SocketConnection_h
#import "GCDAsyncSocket.h" // for TCP

@import CocoaAsyncSocket;

@interface SocketConnection : NSObject <GCDAsyncSocketDelegate>

/* GCDAsyncSocket */
@property (strong, nonatomic) GCDAsyncSocket *socket;


// Methods
+(SocketConnection *)sharedConnection;

@end

#endif /* SocketConnection_h */

SocketConnection.m

#import <Foundation/Foundation.h>
#import "SocketConnection.h"
@implementation SocketConnection

+(SocketConnection *)sharedConnection {
    static dispatch_once_t once;
    static SocketConnection *instance;

    dispatch_once(&once, ^{
        instance = [[SocketConnection alloc] init];
    });


    return instance;
}


-(id)init {

    _socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];

    NSError *err = nil;
    if (![_socket connectToHost:@"http://72.89.157.153" onPort:3000 error:&err]) {
        printf("\nDid Not Return Okay: %s\n", [[err localizedDescription] UTF8String]);
    } else {
        printf("\nReturned Okay\n"); // This is printed
    }

    return self;
}

/* ASNYC DELEGATES */

/* I am expecting this method to be called when connectToHost: is called in init.. */

- (void)socket:(GCDAsyncSocket *)sender didConnectToHost:(NSString *)host port:(UInt16)port {
    printf("I'm connected! Host:%s\n", [host UTF8String]); 
}

- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
    printf("I have written That was easy.\n");


}

- (void)socket:(GCDAsyncSocket *)sender didReadData:(NSData *)data withTag:(long)tag {
    printf("I have read That was easy.\n");

    dispatch_async(dispatch_get_main_queue(), ^{
        @autoreleasepool {
            [_socket readDataWithTimeout:-1 tag:1];
        }


    });

}

@end

Вот точка в ViewController, где я создаю экземпляр SocketConnection...

-(void)viewDidAppear:(BOOL)animated {
    /* Socket connector */
    SocketConnection *s = [SocketConnection sharedConnection];
    printf("port: %hu\n" ,s.socket.connectedPort); // prints 0 right now
}

Если это не лучший способ достижения моей цели, пожалуйста, укажите мне правильное направление (чтение ссылок, другие фреймворки, библиотеки и т. Д.). По любым вопросам, пожалуйста, дайте мне знать.

Спасибо вам за помощь.

1 ответ

Окей, для вашей первой цели (разрешите пользователям отправлять push-уведомления другим пользователям и предполагая, что у вас есть серверная часть node.js с express и mongodb), попробуйте сделать это:

Сначала на стороне сервера установите apn и node-gcm.

npm i --save apn node-gcm

Эти два пакета используются для отправки push-уведомлений на iOS и Android.

После установки этих пакетов создайте маршрут на стороне сервера для отправки уведомлений. Это можно сделать примерно так:

const express = require('express');
const path = require('path');
const gcm = require('node-gcm');
const apn = require('apn');

const apnProvider = new apn.Provider({
  token: {
    // YOU CAN FOUND THIS KEYS AND THE CERTIFICATE ON APPLE DEVELOPERS SITE
    key: path.resolve(__dirname, 'PATH TO YOUR CERTIFICATE.P8'),
    keyId: YOUR APN KEY ID,
    teamId: YOUR APN TEAM ID,
  },
  production: false,
});

router.post('/sendNotification', (req, res) => {
const deviceToken = req.body.token;
const message = req.body.message;
const payload = req.body.payload;
const packages = req.body.package;

switch (packages) {
  case 'com.foo.bar': {
  const notification = new apn.Notification();
  notification.topic = 'com.foo.bar';
  notification.expiry = Math.floor(Date.now() / 1000) + 3600;
  notification.badge = 1;
  notification.sound = 'ping.aiff';
  notification.alert = { message };
  notification.payload = { payload };
  apnProvider.send(notification, deviceToken).then((result) => {
    return result === 200 ? res.sendStatus(200, result) : res.sendStatus(400);
  });
  break;
}
case 'com.yourteam.foo.bar': {
  const androidMessage = new gcm.Message({
    priority: 'high',
    contentAvailable: true,
    delayWhileIdle: false,
    timeToLive: 10,
    restrictedPackageName: 'com.yourteam.foo.bar',
    dryRun: false,
    data: {
      title: 'foo',
      icon: '@mipmap/logo',
      notId: parseInt(Math.random() * new Date().getSeconds(), 10),
      message,
    },
  });
  const sender = new gcm.Sender(YOUR_KEY);
  const registrationTokens = [deviceToken];
  sender.send(androidMessage, { registrationTokens }, (err, response) => {
    return err ? res.send(err) : res.send(response);
  });
  break;
}
default:
  return res.sendStatus(400);
}
});

Теперь, чтобы отправить push-уведомление, вам нужно сделать POST как этот:

IOS

Цель С

#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"content-type": @"application/x-www-form-urlencoded",
                       @"cache-control": @"no-cache"

NSMutableData *postData = [[NSMutableData alloc] initWithData:[@"token=xxxxx" dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:[@"&message=xxxxx" dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:[@"&payload=xxxxx" dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:[@"&package=xxxxx" dataUsingEncoding:NSUTF8StringEncoding]];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://72.89.157.153:3000/notifications/sendNotification"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

СВИФТ

import Foundation

let headers = [
  "content-type": "application/x-www-form-urlencoded",
  "cache-control": "no-cache"
]

let postData = NSMutableData(data: "token=xxxxx".data(using: String.Encoding.utf8)!)
postData.append("&message=xxxxx".data(using: String.Encoding.utf8)!)
postData.append("&payload=xxxxx".data(using: String.Encoding.utf8)!)
postData.append("&package=xxxxx".data(using: String.Encoding.utf8)!)

let request = NSMutableURLRequest(url: NSURL(string: "http://72.89.157.153:3000/notifications/sendNotification")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()

WEB (AJAX)

var settings = {
  "async": true,
  "crossDomain": true,
  "url": "http://72.89.157.153:3000/notifications/sendNotification",
  "method": "POST",
  "headers": {
    "content-type": "application/x-www-form-urlencoded",
    "cache-control": "no-cache"
  },
  "data": {
    "token": "xxxxx",
    "message": "xxxxx",
    "payload": "xxxxx",
    "package": "xxxxx"
  }
}

$.ajax(settings).done(function (response) {
  console.log(response);
});

ДЖАВА

OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "token=xxxxx&message=xxxxx&payload=xxxxx&package=xxxxx");
Request request = new Request.Builder()
  .url("http://72.89.157.153:3000/notifications/sendNotification")
  .post(body)
  .addHeader("content-type", "application/x-www-form-urlencoded")
  .addHeader("cache-control", "no-cache")
  .build();

Response response = client.newCall(request).execute();

Теперь вы можете отправлять push-уведомления на все устройства.

Ваша вторая цель может быть легко достигнута с вашей серверной стороны, когда запрос отправляется на ваш URL, вы можете сделать POST отправку push-уведомления, например, если кто-то хочет добавить вас в друзья (скажем, что они сделали запрос по http://72.89.157.153:3000/friends/{account_id}), вы можете отправить пользователю уведомление о том, что у него есть новый запрос на дружбу.

Важно, чтобы на mongodb вы хранили пакет и токен своих пользователей, чтобы вы могли отправлять нужные уведомления.

Надеюсь, поможет.

Другие вопросы по тегам