iOS Push (Remote) Notification für Jedermann

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

Rabattcode für die heise MacDev 2020: Macoun20

Aufgrund der Corona-Krise: Die Veröffentlichung von Stellenangeboten und -gesuchen ist bis 31.12.2020 kostenfrei. Das beinhaltet auch Angebote und Gesuche von und für Freischaffende und Selbstständige.

  • iOS Push (Remote) Notification für Jedermann

    Push (Remote) Notification für Jedermann

    Nachdem ich jetzt doch recht lange Zeit daran gesessen habe meine App mit Push-Notifications auszurüsten und ich mir dafür alles mögliche von den verschiedensten Stellen im Internet zusammen suchen musste und dennoch Fragen offen blieben dachte ich, ich schreibe mal ein Komplett-Tutorial. Da ich selber ja noch sehr neu in dieser Materie bin und sicher nicht alles perfekt gelöst ist, mag eventuell ja der eine oder andere Crack hier noch seine Meinung dazu abgeben und so wird daraus ein rundes Paket das allen hilft.

    Angemerkt sei noch, dass dieses Tutorial PHP und SQL zum Versenden der Notifications , Registrieren der Devices und Abfragen des Feedback-Services verwendet. Sicher ist das auch mit anderen Scriptsprachen und Datenbanken möglich, aber ich denke diese beiden sind am weitesten verbreitet.

    Das ist keine Anleitung für absolute iOs-Programmier-Anfänger. Es wird davon ausgegangen, dass klar ist wie man AppID‘s, Provisioning Profiles u.ä. anlegt und das Grundlagen in PHP und SQL vorhanden sind.

    Das erste was man benötigt um überhaupt Push-Notifications in seiner App implementieren zu können ist das Push-Zertifikat, welches unser PHP Server benötigt um sich beim Apple-Push-Notification-Service anzumelden.

    Sollte es für die App noch keine AppID geben, dann sollten wir jetzt eine neue anlegen. Danach müssen wir diese erweitern. Dazu klicken wir einfach unter App IDs auf den „Configure“ Button neben unserer AppID und aktivieren dann „Enable for Apple Push Notifcation service“ und klicken dann wieder auf den gerade aktiv gewordenen „Configure“ Button neben dem Zertifikatsnamen. Diese führt uns durch den uns schon bekannten „Certificate Assistant“. Nachdem wir das Zertifikat erstellt und heruntergeladen haben, importieren wir es durch Doppelklick in unseren Schlüsselbund.

    Nun müssen wir dieses Zertifikat ins PEM Format konvertieren.

    Dazu starten wir die Schlüsselbundverwaltung und aktivieren die „Zertifikate“ Kategorie. Dort sehen wir einen aufklappbaren Eintrag „Apple Development Push Services“. Den klappen wir und klicken dann mit der rechten Maustaste auf Apple Development Push Services->“Apple Development Push Services: XXXXXXX“ exportieren und speichern das als apns-dev-cert.p12
    Das gleiche machen wir für den privaten Schlüssel der beim Öffnen erschienen ist und speichern diesen unter apns-dev-key.p12
    Jetzt öffnen wir ein Terminal und konvertieren die beiden Dateien ins PEM Format und verbinden sie miteinander:

    Quellcode

    1. openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12
    2. openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-key.p12
    3. openssl rsa -in apns-dev-key.pem -out apns-dev-key-noenc.pem
    4. cat apns-dev-cert.pem apns-dev-key-noenc.pem > apns-dev.pem


    Der Rest ist relativ einfach. Die PEM Datei muss im gleichen Ordner liegen wie das folgende PHP Script zum Schicken der Notification:

    Quellcode

    1. // notifocation vars
    2. $title='I got news!'; // This is the text shown in the notification
    3. $section=0; // just an example for user data
    4. $type=1;
    5. /* db connect */
    6. define("SQL_HOST","myDBURL"); // host name
    7. define("SQL_USER","UserName"); // user name
    8. define("SQL_PASSWORD","Password"); // password
    9. define("SQL_DBNAME","Database"); // database name
    10. /* connect to db */
    11. function db_connect()
    12. {
    13. global $db;
    14. $db = mysql_connect(SQL_HOST,SQL_USER,SQL_PASSWORD);
    15. if(!$db)
    16. {
    17. echo "Cannot connect to database #1";
    18. die();
    19. }
    20. mysql_select_db(SQL_DBNAME,$db);
    21. }
    22. db_connect();
    23. // create notification string
    24. $payload['aps']=array('alert' => $title, 'badge' => 1,'sound' => 'default');
    25. // this ist just an example how to add userdata to the notification
    26. $payload['data']=array('section' => $section, 'type' => $type);
    27. $payload=json_encode($payload);
    28. // connect data for the apns
    29. $apnsHost='gateway.sandbox.push.apple.com';
    30. $apnsPort=2195;
    31. $apnsCert='apns-dev.pem';
    32. // open stream
    33. $streamContext=stream_context_create();
    34. stream_context_set_option($streamContext,'ssl','local_cert',$apnsCert);
    35. $apns=stream_socket_client('ssl://'.$apnsHost.':'.$apnsPort,$error,$errorString,2,STREAM_CLIENT_CONNECT,$streamContext);
    36. if($error!=0)
    37. {
    38. echo 'Error open stream: '.$error;
    39. echo $errorString;
    40. die();
    41. }
    42. // now push a notification for every registered token
    43. $out = mysql_query("SELECT * FROM uppco_token");
    44. if(!$out)
    45. {
    46. echo "Error reading database. #2 uppco_token";
    47. die();
    48. }
    49. echo 'Start notifying...
    50. ';
    51. while($data=mysql_fetch_array($out))
    52. {
    53. $deviceToken=$data[0];
    54. echo 'Notify: '.$deviceToken.'
    55. ';
    56. $apnsMessage=chr(0).chr(0).chr(32).pack('H*',$deviceToken).chr(0).chr(strlen($payload)).$payload;
    57. fwrite($apns,$apnsMessage);
    58. }
    59. echo '
    60. Notifying done.
    61. ';
    62. fclose($apns);
    63. ?>
    Alles anzeigen


    Als weiteres brauchen wir ein PHP Script, bei dem sich die Devices mit Ihrem DeviceToken anmelden. Das ist ebenfalls recht einfach:

    Quellcode

    1. /* db connect */
    2. define("SQL_HOST","myDBURL"); // host name
    3. define("SQL_USER","UserName"); // user name
    4. define("SQL_PASSWORD","Password"); // password
    5. define("SQL_DBNAME","DataBase"); // database name
    6. /* connect to db */
    7. function db_connect()
    8. {
    9. global $db;
    10. $db = mysql_connect(SQL_HOST,SQL_USER,SQL_PASSWORD);
    11. if(!$db)
    12. {
    13. echo "Error: Cannot connect to database #1";
    14. die();
    15. }
    16. mysql_select_db(SQL_DBNAME,$db);
    17. }
    18. db_connect();
    19. $token=$_GET['token'];
    20. // first check db if token already exists
    21. $out = mysql_query("SELECT * FROM uppco_token WHERE token='".$token."'");
    22. if(!$out)
    23. {
    24. echo "Error: reading database. #2 uppco_token";
    25. die();
    26. }
    27. if($data=mysql_fetch_array($out))
    28. {
    29. echo "Done: token already registered";
    30. die();
    31. }
    32. // if not, insert token in db
    33. $out = mysql_query("INSERT INTO uppco_token (token) VALUES('".$token."')");
    34. if(!$out)
    35. {
    36. echo "Error: writing database. #3 uppco_token";
    37. die();
    38. }
    39. echo 'Done: token registered';
    40. ?>
    Alles anzeigen


    Ein drittes PHP Script dient dazu den Feedback service abzufragen. Hier werden uns z.B. die Tokens der Devices mitgeteilt, die über längere Zeit keine Notifikation angenommen haben. Bei diesen können wir davon ausgehen, dass dort unsere App wieder deinstalliert wurde. Wir können dann also diese DeviceTokens aus unserer DB entfernen. Wie das geht wird hier nicht weiter erklärt. In dem Script geht es nur darum den Feedback richtig abzufragen:

    Quellcode

    1. // create stream
    2. $streamContext = stream_context_create();
    3. stream_context_set_option($streamContext, 'ssl', 'local_cert', 'apns-dev.pem');
    4. stream_context_set_option($streamContext, 'ssl', 'verify_peer', false);
    5. // assume the private key passphase was removed.
    6. // stream_context_set_option($streamContext, 'ssl', 'passphrase', $pass);
    7. $apns = stream_socket_client('ssl://feedback.sandbox.push.apple.com:2196', $error, $errorString, 60, STREAM_CLIENT_CONNECT, $streamContext);
    8. // production server is ssl://feedback.push.apple.com:2196
    9. if (!$apns || $error)
    10. {
    11. echo 'Failed to connect feedback server: $err $errstr
    12. ';
    13. die();
    14. }
    15. else
    16. {
    17. echo 'Connection to feedback server OK
    18. ';
    19. }
    20. echo 'APNS feedback results:
    21. ';
    22. while ($devcon = fread($apns, 38))
    23. {
    24. $arr = unpack("H*", $devcon);
    25. $rawhex = trim(implode("", $arr));
    26. $feedbackTime = hexdec(substr($rawhex, 0, 8));
    27. $feedbackDate = date('Y-m-d H:i', $feedbackTime);
    28. $feedbackLen = hexdec(substr($rawhex, 8, 4));
    29. $feedbackDeviceToken = substr($rawhex, 12, 64);
    30. echo 'TIMESTAMP:' . $feedbackDate . '
    31. ';
    32. echo 'DEVICE ID:' . $feedbackDeviceToken. '
    33. ';
    34. }
    35. echo 'All results done.';
    36. fclose($apns);
    37. ?>
    Alles anzeigen
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Nun kommen wir zum eigentlich Code in unserer App. Zunächst brauchen wir eine NSOperationQueue um unsere Registrierung mit dem Server im Hintergrund ablaufen zu lassen, da der HHTP Request schon eine Weile dauern kann und wir damit nicht das App blockieren wollen. Weiterhin brauchen wir eine Funktion die all das notwendige macht, wenn unsere App eine Notification erhält.

    Quellcode

    1. @interface MyAppDelegate : NSObject <UIApplicationDelegate>
    2. {
    3. // Die OperationQueue benötigen wir um uns im Hintergrund bei unserem Server zu registrieren.
    4. NSOperationQueue *queue;
    5. ....
    6. }
    7. @property (nonatomic, retain) NSOperationQueue *queue;
    8. ....
    9. // Diese Funktion macht was auch immer nötig ist wenn die App durch eine
    10. // Notification gestartet wird.
    11. -(void)handleUserInfo:(NSDictionary*)userInfo;
    12. ....
    13. - (void)dealloc
    14. {
    15. ...
    16. [queue release];
    17. [super dealloc];
    18. }
    Alles anzeigen


    Dann brauchen wir drei Funktionen in unserem AppDelegate]

    Quellcode

    1. - (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken
    2. {
    3. // wir starten die Registrierung im Hintergrund
    4. if(queue)
    5. {
    6. BackgroundLoader *backLoader=[[BackgroundLoader alloc] initWithToken:devToken];
    7. if(backLoader)
    8. {
    9. [queue addOperation:backLoader];
    10. [backLoader release];
    11. }
    12. }
    13. }
    14. - (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err
    15. {
    16. // Tja hier machen wir was immer wir wollen wenn die Registrierung fehlgeschlagen hat
    17. myLog(@"Error in registration. Error: %@", err);
    18. }
    19. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
    20. {
    21. // und hier behandeln wir eine eigehende Notification. Dabei steht in der userInfo genau das was wir auf unserem Server in den $payload geschrieben haben.
    22. [self handleUserInfo:userInfo];
    23. }
    Alles anzeigen


    Des weiteren müssen wir dem iOs sagen das wir Bereit sind Notifications zu erhalten.

    Quellcode

    1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    2. {
    3. myLog(@"LaunchOptions %@",launchOptions);
    4. [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
    5. [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
    6. // und legen auch gleich die queue an.
    7. queue = [[NSOperationQueue alloc] init];
    8. // Wenn die App von einer Notification gestartet wird und nicht nur in den Vordergrund geholt, dann gibt es in den launchOptions einen key „UIApplicationLaunchOptionsRemoteNotificationKey“ in welchem
    9. // wiederum unsere userInfo der Notification steht. Da in dem Fall NICHT noch extra didReceiveRemoteNotification() aufgerufen wird, müssen wir die Notification hier direkt behandeln.´
    10. if(launchOptions)
    11. {
    12. NSDictionary *userInfo=[launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"];
    13. if(userInfo)
    14. [self handleUserInfo:userInfo];
    15. };
    16. ....
    17. }
    Alles anzeigen


    Zu guter letzt fehlt uns jetzt nur noch der Thread welcher das Device bei unserem Server registriert.

    Quellcode

    1. @interface BackgroundLoader : NSOperation
    2. {
    3. NSData *token; // for notification registration
    4. }
    5. @property (nonatomic, retain) NSData *token;
    6. -(id)initWithToken:(NSData*)deviceToken;
    7. -(BOOL)sendProviderDeviceToken:(NSData*)deviceToken;
    8. -(id)initWithToken:(NSData*)deviceToken
    9. {
    10. if((self=[super init])!=nil)
    11. {
    12. self.token=deviceToken;
    13. }
    14. return self;
    15. }
    16. -(void)main
    17. {
    18. myLog(@"Backgroundloader running...");
    19. // there is nothing to do if no internet is avaible
    20. if(token)
    21. {
    22. [self sendProviderDeviceToken:token];
    23. }
    24. }
    25. -(BOOL)sendProviderDeviceToken:(NSData*)deviceToken
    26. {
    27. // erstmal nachsehen ob bereits registriert. Dann können wir uns das sparen
    28. NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    29. if([userDefaults objectForKey:“AppRegistered“]==nil)
    30. {
    31. // nun das token in einen gültinge HexString wandeln
    32. const char * data = [deviceToken bytes];
    33. NSMutableString* tokenString = [NSMutableString string];
    34. for (int i = 0; i < [deviceToken length]; i++)
    35. {
    36. [tokenString appendFormat:@"%02.2hhX", data[i]];
    37. }
    38. myLog(@"Register with Token: %@",tokenString);
    39. NSURL* registerurl = [NSURL URLWithString:[NSString stringWithFormat:@"%@register.php5?token=%@", @“http://www.meineurl.de/,tokenString]];
    40. myLog(@"Register with URL: %@",registerurl);
    41. NSMutableURLRequest* request = [[[NSMutableURLRequest alloc] initWithURL:registerurl] autorelease];
    42. NSURLResponse *response=nil;
    43. NSError *error=nil;
    44. NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    45. NSString* returnString = [[NSString alloc] initWithData:returnData encoding:NSASCIIStringEncoding];
    46. myLog(@"Register Response: %@",response);
    47. myLog(@"Register Errror: %@",error);
    48. myLog(@"Register Return: %@",returnString);
    49. if(error==nil)
    50. {
    51. // Fehlerfrei geklappt?
    52. if([[returnString substringToIndex:6] compare:@"Done"])
    53. {
    54. myLog(@"Register succesful");
    55. [userDefaults setInteger:1 forKey:@“AppRegistered“];
    56. [returnString release];
    57. return YES;
    58. }
    59. }
    60. [returnString release];
    61. return NO;
    62. }
    63. return YES;
    64. }
    65. -(void)dealloc
    66. {
    67. [token release];
    68. [super dealloc];
    69. }
    Alles anzeigen


    Das ist alles was wir brauchen. Wer genaueres über den Aufbau der payloads haben möchte, kann dieses in der Apple Doku nachlesen.
    AppleDoku
    Diese Anleitung bezieht sich auf das simple notification format. Ein Umbau auf das enhanced notification format sollte aber kein Problem sein.

    Viel Spaß damit

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Thallius ()

  • Moin,

    um andere vor diesem Fehler zu bewahren, möchte ich mein Tutorial an dieser Stelle um einen Tipp erweitern.

    Ich habe den Fehler gemacht und habe die Tokendatenbank von der Beta in die Release übernommen und einfach nur die alten Beta-Token gelöscht. Was ich nicht bedacht hatte war, dass ja durchaus noch einer der Tester auf die Idee kommen könnte seine App noch einmal zu starten und so kam es natürlich auch.
    Die Folge daraus war, dass ein Beta-Token in der Release Datenbank erschien.
    Ein großes Problem deshalb, weil Apple in dem Moment wo man einen invaliden Token schickt die Pipe abbricht. Da das ja durchaus auch mal auf anderem Wege passieren kann, habe ich mir überlegt das Ganze gleich richtig zu korregieren.

    Das geht aber nur wenn ich nicht mehr das simple Format benutze und ich muste auf das enhance Format umsteigen, um eine Rückmeldung von Apple zu erhalten wenn ein invalider Token auftritt. Dummerweise bekomme ich den Fehler nicht direkt gemeldet sondern das Ganze läuft asynchron. Was muss ich also tun?

    Zunächst schicke ich mit jedem Token eine uniqueID als identifier mit der Notification (In meinem Fall einfach die Zählvariable der Schleife durch die Token).
    Dann muss ich nach jedem fwrite abfragen ob dieser geklappt hat. Ist er fehlgeschlagen, weiß ich, daß Apple die Verbindung gekappt hat. Ich weiß aber noch nicht wann. Das kann nämlich schon 30 oder mehr Token früher gewesen sein. Deshalb lese ich mir die mitgelieferte uniqueId aus, schließe den kaputten Stream, öffne einen neuen und fange dort bei der uniqueId +1 wieder an meine Notifications zu senden.

    Das ist im Prinzip sehr einfach. In der App muss dafür nichts geändert werden. Ledgilich im PHP Script sind einige Änderungen notwendig. Das nun folgende Script ist sicher nicht das Maß der Dinge sondern eher quick und dirty, aber es veranschaulicht ziemlich gut wie man so etwas realisieren kann.

    Quellcode

    1. /* connect to db */
    2. global $db;
    3. $db = mysql_connect(SQL_HOST,SQL_USER,SQL_PASSWORD);
    4. if(!$db)
    5. {
    6. echo "Es kann keine Verbindung zur lokalen Datenbank hergestellt werden: #1";
    7. }
    8. else
    9. {
    10. mysql_select_db(SQL_DBNAME,$db);
    11. $title=utf8_encode($title);
    12. // create notification string
    13. $payload['aps']=array('alert' => $title, 'badge' => 1,'sound' => 'default');
    14. $payload['data']=array('section' => $section, 'type' => $type);
    15. $payload=json_encode($payload);
    16. // connect data for the apns
    17. $apnsHost='gateway.push.apple.com';
    18. $apnsPort=2195;
    19. $apnsCert=certificat.pem';
    20. // echo $section.'/'.$type.' - '.$title.'<br><br'; // for debug
    21. echo 'Beginne mit der Benachrichtigung...<br><br>';
    22. $starttoken=0; // for retry on error
    23. $open=FALSE; // open and reopen stream in loop if closed from apple
    24. $loop=TRUE; // finish when all tokens send
    25. while($loop==TRUE)
    26. {
    27. // fetch all token
    28. $out = mysql_query("SELECT * FROM iphoneapp");
    29. if(!$out)
    30. {
    31. echo "Beim Lesen der lokalen Datenbank ist ein Fehler aufgetretern: #2";
    32. break;
    33. }
    34. $i=0; // my counter for the unique id of the message
    35. while($data=mysql_fetch_array($out))
    36. {
    37. // token already send ?
    38. if($i>=$starttoken)
    39. {
    40. // stream is open ?
    41. if($open==FALSE)
    42. {
    43. $streamContext=stream_context_create();
    44. stream_context_set_option($streamContext,'ssl','local_cert',$apnsCert);
    45. $apns=stream_socket_client('ssl://'.$apnsHost.':'.$apnsPort,$error,$errorString,60,STREAM_CLIENT_CONNECT,$streamContext);
    46. if($error!=0)
    47. {
    48. echo 'Der Output Stream konnte nicht geöffnet werden: '.$error;
    49. echo $errorString;
    50. // cant open stream so abort all
    51. $loop=FALSE;
    52. break;
    53. }
    54. $open=TRUE;
    55. }
    56. $deviceToken=$data[0];
    57. $deviceToken=str_replace(' ', '', $deviceToken);
    58. echo 'Nachricht an: '.$deviceToken.'<br>';
    59. // create the enhanced notification message
    60. $apnsMessage = chr(1).pack("N",$i).pack("N",0).pack("n",32).pack("H*",$deviceToken).pack("n",strlen($payload)).$payload;
    61. // and write to stream
    62. if(fwrite($apns,$apnsMessage)==FALSE)
    63. {
    64. // if write failed read return from APNS server
    65. $buffer=fgets($apns);
    66. if($buffer)
    67. {
    68. $text=unpack("c2chars/Nint",$buffer);
    69. if($text['chars1']==8) // invalid token error
    70. {
    71. // set net starttoken to invalid token +1
    72. $starttoken=$text['int']+1;
    73. echo 'Benachrichtigung ab Nummer: '.$starttoken.' fehlgeschlagen. Fange danach wieder an.<br>';
    74. // break inner loop
    75. break;
    76. }
    77. }
    78. }
    79. }
    80. $i++;
    81. }
    82. // close already broken stream
    83. if($open==TRUE)
    84. {
    85. fclose($apns);
    86. $open=FALSE;
    87. }
    88. // no more data ? then we are finished
    89. if(!$data)
    90. break;
    91. }
    92. echo '<br><br>Benachrichtigungen alle versandt.<br><br>';
    93. }
    Alles anzeigen


    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Hallo Thallius,

    danke für das sehr gute Tutorial. Die ersten Pushnachrichten haben heute mein iPhone erreicht :)
    Habe das ganze in eine Zend Framework Umgebung eingebaut, mit ein paar Änderungen hat das super geklappt.

    Ein paar Probleme habe ich noch :
    - Die Badges zeigen immer 1 und werden auch nicht zurück gesetzt.
    - Kann ich auch einen anderen Ton spielen?
    - Welche Möglichkeiten habe ich die Notifications zu formatieren? bzw. geht da überhaupt was?

    Vielleicht hast du ja noch einen gute Link...

    Eine Frage habe ich noch:
    -(void)handleUserInfo:(NSDictionary*)userInfo;

    Was kann ich in der Funktion alles machen und wie hast du die Funktion debugt?

    Danke für deine Hilfe,
    Urkman
  • Hi,
    Hab das gerade mal kurz alles überflogen und dabei ist mir aufgefallen, dass dein PHP-Script überhaupt nicht vor SQL-Injections geschützt ist.

    Zum beispiel die Abfrage beim Anmelden des Device:
    $out = mysql_query("SELECT * FROM uppco_token WHERE token='".$token."'");

    Wenn irgendwer die passende URL zu dem Script findet kannst du dich von deiner Tabelle/Datenbank verabschieden.
    Ansonsten sieht es echt interessant aus, auch wenn ich derzeit noch keine Verwendung dafür habe.
  • Creativ schrieb:

    Hi,
    Hab das gerade mal kurz alles überflogen und dabei ist mir aufgefallen, dass dein PHP-Script überhaupt nicht vor SQL-Injections geschützt ist.

    Zum beispiel die Abfrage beim Anmelden des Device:
    $out = mysql_query("SELECT * FROM uppco_token WHERE token='".$token."'");

    Wenn irgendwer die passende URL zu dem Script findet kannst du dich von deiner Tabelle/Datenbank verabschieden.
    Ansonsten sieht es echt interessant aus, auch wenn ich derzeit noch keine Verwendung dafür habe.


    Hi,

    ich habe das doch auch geschrieben, dass es nur eine sehr einfaches Script ist, damit man das Prinzip versteht. Ich gehe davon aus, dass wer sowas macht sich mit PHP Oder entsprechend anderen Schriftsprachen entsprechend auskennt und in der Lage ist, dass für ihn wichtige zu entnehmen und das sonst notwendige hinzuzufügen. Das soll ja kein fertiges Framework zum kopieren sein, sondern eine Anleitung zum Verstehen. Wenn ich da alles reinpacke was nicht unmittelbar mit der Funktionalität zu tun hat (und dazu zähle ich auch Sicherheitsmechanismen), dann kapiert es ja wieder keiner :)

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Hallo zusammen,

    wie macht ihr den Badge Count? Würde gerne für jede neue Nachricht die Badge Zahl um 1 erhöhen...

    Ich überlege das in Verbindung mit dem Device Token zu machen. Also immer, wenn ich die Badge am App Icon zurück setze, den DiviceToken zu verschicken und so auch auf dem Server den Count auf 0 zu setzen.

    Oder gibt es da einen besseren Weg?

    Danke und Grüße,
    Urkman
  • Hallo,

    erstmal danke für dein Tutorial, ist einfach und verständlich geschrieben und beschränkt sich auf das wesentliche :)

    Nun hab ich aber noch eine Frage.

    Szenario:
    Ich bekomme eine Push-Nachricht und reagiere nicht sofort auf diese, d. h. ich gehe nicht sofort in die App. Es erscheint bei meiner App die Badge mit einer "1" zum Beispiel.
    Dann rufe ich die App auf und möchte natürlich trotzdem die Informationen aus dem Body der Push-nachricht verwenden.

    Nun zu meiner Frage,
    Wie komme ich an diese Informationen?
    Wenn ich die Pushnachricht sofort öffne kann ich über die Methode "- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo " die im Body enthaltenen Informationen auslesen.
    Aber wie mach ich das in meinem Fall bzw. geht das überhaupt dann noch?

    Wäre super wen mir da jemand weiterhelfen könnte

    Gruß
    Ava
  • Ich habe das mitlerweile so gelößt, dass ich eine eigene Tabelle in der SQL Datenbank angelegt habe, in die jede Msg eingetragen wird. Sobald eine App gestartet wird, fragt diese ab ob es msgs für sie in dieser Tabelle gibt und behandelt sie entsprechend. Danach werden sie gelöscht.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Hab es auch ähnlich gelöst, bloss schicke ich nun einen Push raus der alle relavanten Daten enthält. Diese werden dann ähnlich wie bei dir zwischengespeichert bis sie abgearbeitet sind.

    Nun habe ich aber ein Problem mit den Devicetoken, diese sind nämlich komsicherweise in der Developerversion anders als im eigentlichen Release. Das Problem ist dann das ich in der Releaseversion die Geräte nicht mehr anpushen kann.
    Habt ihr eine Idee woran das liegen könnte? Ich vermute das es villeicht auch an den Zertifikaten liegt hab das aber noch nicht getestet.

    Gruß Ava
  • Nein das ist so. Du must für Developer und Release ja auch zwei verschiedene Adressen und Zertifikate angeben. Du solltest deshalb auch auf jeden Fall für Developer und Release zwei verschiedene SQL Tabellen nehmen. Denn die Developer Token erzeugen bei dem Release Push einen Fehler und brechen Dir die Pipe. Sehr unschön.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Danke für deine Infos, hab ich umgesetzt. War mal wieder ein Kampf mit dem Zertifikaten aber geschafft ^^

    Nun hab ich ein anderes Problem. Wenn ich eine Pushnachricht bekomme und

    1. Variante
    Die App im Hintergrund läuft

    2. Variante
    Die App durch die Pushnachricht gestartet wird

    Bei der 1. Variante ist alles wunderbar und ich kann den Body auslesen und verarbeiten/speichern, durch die Funktion
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo

    Bei der 2. Variante wird nun die App gestartet, aber die obige Funktion wird nicht aufgerufen! Und somit gehen meine Informationen aus der Pushnachricht verloren :(
    Eigentlich kein Problem, denn ich kann bei meinem Server anfragen ob es einen Push an mich gab. Dies möchte ich aber nur machen, wenn die App auch wirklich durch eine Pushnachricht gestartet wurde.

    Nun meine Frage, Wie merke ich z. B. in der
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    ob meine App durch Pushnachricht gestartet wurde oder ganz normal über das Appicon? Hab ich da überhaupt eine Möglichkeit?

    Danke schonmal für Antworten, Anregungen etc.

    Gruß
    Ava
  • Die Push-Nachrichten laufen bei mir.
    Wie bekomme ich es aber, wie bei der myFitApp hin? myfitapp.de/fitnessstudio-app/push-nachrichten/
    Im letzten Abschnitt der Seite, diese "Multimedia Push-Nachrichten"?

    Also ich möchte, dass nachdem die Push Nachricht angekommen und ich auf "Anzeigen" klicke, in die App weitergeleitet werde und dort so eine Nachricht wie auf der Seite lesen kann. Außerdem sollte es möglich sein, dann in der App die letzten Nachrichten lesen zu können.

    Wie wird das gemacht?
  • Ok, danke für die Antwort.
    Alerdings bin ich ja dadurch an UrbanAirship bei der Erstellung meiner Push-Nachricht gebunden. Noch dazu kostet es im kleinsten Paket 199$.

    Es wäre schon gut, wenn das ganze unabhängig von einem Dienstanbieter laufen würde.

    Bin nur im Moment etwas überfragt, wie das gehen soll. Kann mir auch nicht vorstellen, dass myFitApp UrbanAirship.com für den Push Dienst nutzt.