2017-05-16 2 views
0

Ich versuche, eine FCM-Gerätegruppe für einen meiner Benutzer zu schaffen, aber wenn die create Anfrage ich Entsendung 401 reponse code:erstellen FCM Gerätegruppe gibt 401

Hier ist meine POST Anfrage:

if let url = URL(string: "https://android.googleapis.com/gcm/notification") { 
     var request = URLRequest(url: url) 
     request.httpMethod = "POST" 
     request.addValue("application/json", forHTTPHeaderField: "Content-Type") 
     request.addValue("application/json", forHTTPHeaderField: "Accept") 
     request.addValue(apiKey, forHTTPHeaderField: "Authorization") 
     request.addValue(senderId, forHTTPHeaderField: "project_id") 

     let registration_ids = [deviceToken] as! [String] 
     let jsonToSend = ["operation": "create", 
          "notification_key_name": LocalUser.shared.firebaseId, 
          "registration_ids": registration_ids 
      ] as [String : Any] 

     do { 
      let jsonData = try JSONSerialization.data(withJSONObject: jsonToSend, options: JSONSerialization.WritingOptions.prettyPrinted) 
      request.httpBody = jsonData 

      let task = URLSession.shared.dataTask(with: request) { data, response, error in 
       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.debugDescription)") 
       } else if let httpStatus = response as? HTTPURLResponse { 

        print("statusCode is \(httpStatus.statusCode)") 
        print("response = \(response.debugDescription)") 

       } 
      } 
      task.resume() 
     } catch { 
      print("could not serialize json") 
     } 
    } 

Wissen Sie auch, was passiert, wenn ich versuche, eine device group mit einer bereits bestehenden notification_key_name zu erstellen. Wird die neue device key zur bestehenden Gruppe hinzugefügt? Oder gibt es eine Möglichkeit zu überprüfen, ob eine Gruppe existiert?

+0

Ist dies getan Client-Seite oder auf einem Server? Es muss über einen Server erfolgen. –

+0

ist es Client-Seite getan ... sollte ich es stattdessen mit Cloud-Funktionen tun? auch was ist falsch mit der Client-Seite zu tun? – John

+1

https://firebase.google.com/docs/cloud-messaging/ios/device-group - Die grundlegende Verwaltung von Gerätegruppen - Erstellen und Entfernen von Gruppen sowie Hinzufügen oder Entfernen von Geräten - erfolgt normalerweise über den Anwendungsserver Die HTTP-Protokollreferenz für eine Liste der unterstützten Schlüssel. Optional können Android-Client-Apps Gerätegruppen von der Clientseite aus verwalten. " –

Antwort

1

In dieser Erklärung:

request.addValue(apiKey, forHTTPHeaderField: "Authorization") 

apiKey muss von key= der Server Key aus den Projekteinstellungen, vorangestellt werden. Zum Beispiel: key=AAAPWK_CVGw:APA91b...saklHTO29fTk

Sie geben in einem Kommentar an, dass Sie dies von einem Clientgerät aus tun. Das Einstecken Ihres Serverschlüssels in den Gerätecode ist nicht sicher.

Eine sicherere Alternative ist die Erstellung der Gerätegruppe in einer Cloud-Funktion. Im Folgenden finden Sie eine grundlegende Implementierung, die durch das Speichern der Gruppenerstellungsparameter in der Datenbank ausgelöst wird. Nur Beispiel; nicht gründlich getestet; Korrekturen/Kommentare erwünscht.

const rqstProm = require('request-promise'); 

const functions = require('firebase-functions'); 
const admin = require('firebase-admin'); 
admin.initializeApp(functions.config().firebase); 

exports.createDeviceGroup = functions.database.ref("/deviceGroup/create/params") 
     .onWrite(event => { 
    const serverKey = 'AAAAXp6june:APA91bF-Nq9pm...3dD5pZxVsNBfX0O3_Xf-jV472nfn-sb'; 
    const senderId = '271828182845'; 
    // TODO add checks for valid request params 
    const request = event.data.val(); 
    const groupName = request.groupName; 
    const tokens = Object.keys(request.tokens); 

    console.log('groupName=', groupName, 'tokens=', tokens.length); 

    const options = { 
     method: 'POST', 
     uri: 'https://android.googleapis.com/gcm/notification', 
     headers: { 
      'Authorization': 'key=' + serverKey, 
      'project_id': senderId 
     }, 
     body: { 
      operation: 'create', 
      notification_key_name: groupName, 
      registration_ids: tokens 
     }, 
     json: true 
    }; 

    const resultRef = admin.database().ref('deviceGroup/create/result/key'); 

    return rqstProm(options) 
     .then((parsedBody) => { 
      console.log('SUCCESS response=', parsedBody); 
      return resultRef.set(parsedBody.notification_key); 
     }) 
     .catch((err) => { 
      console.log('FAILED err=', err); 
      return resultRef.set('ERROR: ' + err); 
     }); 
}); 

Beispielcode (Android) für eine Gerätegruppe zu schaffen, die Cloud-Funktion mit:

private ValueEventListener resultListener; 

private void createDeviceGroup(String groupName, String ...deviceTokens) { 
    final DatabaseReference baseRef = 
      FirebaseDatabase.getInstance().getReference("deviceGroup/create"); 

    final DatabaseReference resultRef = baseRef.child("result"); 

    // listener to get the result of the group creation request 
    resultListener = new ValueEventListener() { 
     @Override 
     public void onDataChange(DataSnapshot snap) { 
      if (snap.exists()) { 
       // got the result; stop listening 
       resultRef.removeEventListener(resultListener); 
       String key = snap.child("key").getValue(String.class); 
       Log.d(TAG, "createDeviceGroup: key=" + key); 
      } else { 
       // we get here when listener is first attached 
       Log.w(TAG, "createDeviceGroup: No Result"); 
      } 
     } 

     @Override 
     public void onCancelled(DatabaseError databaseError) { 
      resultRef.removeEventListener(resultListener); 
      throw databaseError.toException(); 
     } 
    }; 

    // remove any previous result 
    resultRef.removeValue(); 
    // start listening for a result 
    resultRef.addValueEventListener(resultListener); 

    // build the request params 
    final Map<String,Object> request = new HashMap<>(); 
    final Map<String,Object> tokens = new HashMap<>(); 
    // creation of device group requires a name and set of tokens 
    request.put("groupName", groupName); 
    request.put("tokens", tokens); 

    for (String token : deviceTokens) { 
     // tokens are stored as keys; value is not significant 
     tokens.put(token, true); 
    } 
    // write the request; this triggers Cloud Function to create device group 
    baseRef.child("params").setValue(request); 
} 

Dies ist das Datenbank-Layout nach einer erfolgreichen Gruppenerstellung:

{ 
    "deviceGroup": { 
    "create": { 
     "params": { 
     "groupName": "testGroupA", 
     "tokens": { 
      "ccVDiSO1tbc:APA91bE3pELSz...oDqY_ioLRj4xUnk5mci6ateFRVe" : true, 
      "pqUYfyTbuax:APA91bE3pELSz...oDqY_ioLRj4xUnk5mci6ateFRVe" : true, 
      "tyKUY1mrUR8:APA91bE3pELSz...oDqY_ioLRj4xUnk5mci6ateFRVe" : true 
     } 
     }, 
     "result": { 
     "key": "APA91bEY678qaLUAB1tOPv...tZ9IG64H7b0KtOo-hSJdsoovmuRe2eCyoUeu4qs" 
     } 
    } 
    } 
} 
+0

versuchte, den Serverschlüssel mit dem Präfix hinzuzufügen, aber jetzt gibt die Funktion '400' zurück. Wie auch immer ... wegen des Sicherheitsproblems werde ich den clientseitigen Fall löschen. Ich fragte mich, was könnte eine gute Architektur sein, um es mit "Cloud-Funktionen" zu tun. Vielleicht haben Sie eine Tabelle mit ausstehenden Operationen und hören sich Ereignisse an? – John

+1

@John: Definitiv machbar mit Cloud-Funktionen. Ich habe noch nicht genug Erfahrung, um ein Design zu empfehlen. Klingt wie du auf der richtigen Spur. –

+1

@John: Ich habe meine Antwort aktualisiert. Ich musste etwas über das Auslösen von Cloud-Funktionen lernen, um serverseitige Operationen durchzuführen, also gab es eine Chance. Vielleicht gibt es dir ein paar Ideen. Es kann verbessert werden, da bin ich mir sicher. –

Verwandte Themen