\n\u003Cuses-permission android:name=\"com.synyx.cloudmessagetest.permission.C2D_MESSAGE\"/>\n \u003C!-- App receives GCM messages. -->\n\u003Cuses-permission android:name=\"com.google.android.c2dm.permission.RECEIVE\"/>\n \u003C!-- GCM connects to Google Services. -->\n\u003Cuses-permission android:name=\"android.permission.INTERNET\"/>\n \u003C!-- GCM requires a Google account. -->\n\u003Cuses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>\n \u003C!-- Keeps the processor from sleeping when a message is received. -->\n\u003Cuses-permission android:name=\"android.permission.WAKE_LOCK\"/>\n","xml","",[56,57,58,67,73,79,85,91,97,103,109,115,121,127,133],"code",{"__ignoreMap":54},[59,60,63],"span",{"class":61,"line":62},"line",1,[59,64,66],{"emptyLinePlaceholder":65},true,"\n",[59,68,70],{"class":61,"line":69},2,[59,71,72],{},"\u003Cpermission\n",[59,74,76],{"class":61,"line":75},3,[59,77,78],{}," android:name=\"com.synyx.cloudmessagetest.permission.C2D_MESSAGE\"\n",[59,80,82],{"class":61,"line":81},4,[59,83,84],{}," android:protectionLevel=\"signature\"/>\n",[59,86,88],{"class":61,"line":87},5,[59,89,90],{},"\u003Cuses-permission android:name=\"com.synyx.cloudmessagetest.permission.C2D_MESSAGE\"/>\n",[59,92,94],{"class":61,"line":93},6,[59,95,96],{}," \u003C!-- App receives GCM messages. -->\n",[59,98,100],{"class":61,"line":99},7,[59,101,102],{},"\u003Cuses-permission android:name=\"com.google.android.c2dm.permission.RECEIVE\"/>\n",[59,104,106],{"class":61,"line":105},8,[59,107,108],{}," \u003C!-- GCM connects to Google Services. -->\n",[59,110,112],{"class":61,"line":111},9,[59,113,114],{},"\u003Cuses-permission android:name=\"android.permission.INTERNET\"/>\n",[59,116,118],{"class":61,"line":117},10,[59,119,120],{}," \u003C!-- GCM requires a Google account. -->\n",[59,122,124],{"class":61,"line":123},11,[59,125,126],{},"\u003Cuses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>\n",[59,128,130],{"class":61,"line":129},12,[59,131,132],{}," \u003C!-- Keeps the processor from sleeping when a message is received. -->\n",[59,134,136],{"class":61,"line":135},13,[59,137,138],{},"\u003Cuses-permission android:name=\"android.permission.WAKE_LOCK\"/>\n",[18,140,141],{},"And declare a GCM broadcast receiver within the application tag:",[49,143,145],{"className":51,"code":144,"language":53,"meta":54,"style":54},"\n\u003Creceiver\n android:name=\"com.google.android.gcm.GCMBroadcastReceiver\"\n android:permission=\"com.google.android.c2dm.permission.SEND\">\n \u003Cintent-filter>\n \u003Caction android:name=\"com.google.android.c2dm.intent.RECEIVE\"/>\n \u003Caction android:name=\"com.google.android.c2dm.intent.REGISTRATION\"/>\n \u003Ccategory android:name=\"com.synyx.cloudmessagetest\"/>\n \u003C/intent-filter>\n\u003C/receiver>\n\u003Cservice android:name=\".GCMIntentService\"/>\n",[56,146,147,151,156,161,166,171,176,181,186,191,196],{"__ignoreMap":54},[59,148,149],{"class":61,"line":62},[59,150,66],{"emptyLinePlaceholder":65},[59,152,153],{"class":61,"line":69},[59,154,155],{},"\u003Creceiver\n",[59,157,158],{"class":61,"line":75},[59,159,160],{}," android:name=\"com.google.android.gcm.GCMBroadcastReceiver\"\n",[59,162,163],{"class":61,"line":81},[59,164,165],{}," android:permission=\"com.google.android.c2dm.permission.SEND\">\n",[59,167,168],{"class":61,"line":87},[59,169,170],{}," \u003Cintent-filter>\n",[59,172,173],{"class":61,"line":93},[59,174,175],{}," \u003Caction android:name=\"com.google.android.c2dm.intent.RECEIVE\"/>\n",[59,177,178],{"class":61,"line":99},[59,179,180],{}," \u003Caction android:name=\"com.google.android.c2dm.intent.REGISTRATION\"/>\n",[59,182,183],{"class":61,"line":105},[59,184,185],{}," \u003Ccategory android:name=\"com.synyx.cloudmessagetest\"/>\n",[59,187,188],{"class":61,"line":111},[59,189,190],{}," \u003C/intent-filter>\n",[59,192,193],{"class":61,"line":117},[59,194,195],{},"\u003C/receiver>\n",[59,197,198],{"class":61,"line":123},[59,199,200],{},"\u003Cservice android:name=\".GCMIntentService\"/>\n",[18,202,203],{},"The GCMIntentService has to be created by us. And that is what we’ll do now. First off, the GCMIntentService has to\nextend the class GCMBaseIntentService:",[49,205,209],{"className":206,"code":207,"language":208,"meta":54,"style":54},"language-java shiki shiki-themes github-light github-dark","public class GCMIntentService extends GCMBaseIntentService {\n","java",[56,210,211],{"__ignoreMap":54},[59,212,213],{"class":61,"line":62},[59,214,207],{},[18,216,217],{},"Now implement all the necessary methods. The only method we will use for this little test is onMessage(). We want to\nquickly see if we get a message for this app, so that we can confirm that it works. So we just create a notification\nwith the Notification Builder.",[18,219,220],{},"Because we are on an older minimum version of Android, we need to add the support library to have access to the\nNotification Builder. Add it by right clicking the project -> Android tools -> Add Support Library.",[18,222,223],{},"First in the onMessage() method, we need to get access to the Main Thread of our App.",[49,225,227],{"className":206,"code":226,"language":208,"meta":54,"style":54},"Handler h = new Handler(Looper.getMainLooper());\nh.post(new Runnable() {\n public void run() {\n }\n}\n",[56,228,229,234,239,244,249],{"__ignoreMap":54},[59,230,231],{"class":61,"line":62},[59,232,233],{},"Handler h = new Handler(Looper.getMainLooper());\n",[59,235,236],{"class":61,"line":69},[59,237,238],{},"h.post(new Runnable() {\n",[59,240,241],{"class":61,"line":75},[59,242,243],{}," public void run() {\n",[59,245,246],{"class":61,"line":81},[59,247,248],{}," }\n",[59,250,251],{"class":61,"line":87},[59,252,253],{},"}\n",[18,255,256],{},"In the run() method, we get us an Intent from our MainActivity",[49,258,260],{"className":206,"code":259,"language":208,"meta":54,"style":54},"Intent notificationIntent = new Intent(context, CloudMessageTestActivity.class);\n",[56,261,262],{"__ignoreMap":54},[59,263,264],{"class":61,"line":62},[59,265,259],{},[18,267,268],{},"And then wrap it with a PendingIntent for the NotificationBuilder",[49,270,272],{"className":206,"code":271,"language":208,"meta":54,"style":54},"PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,\n notificationIntent, 0);\n",[56,273,274,279],{"__ignoreMap":54},[59,275,276],{"class":61,"line":62},[59,277,278],{},"PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,\n",[59,280,281],{"class":61,"line":69},[59,282,283],{}," notificationIntent, 0);\n",[18,285,286],{},"Finally, use the NotificationBuilder to create and send the notification",[49,288,290],{"className":206,"code":289,"language":208,"meta":54,"style":54},"NotificationCompat.Builder builder = new NotificationCompat.Builder(\n context);\nbuilder.setContentIntent(pendingIntent);\nbuilder.setAutoCancel(true);\nbuilder.setSmallIcon(R.drawable.ic_launcher);\n//this is added on the server side\nString text = intent.getStringExtra(\"text\");\nbuilder.setContentText(text);\nbuilder.setContentTitle(\"New message from the cloud!\");\nNotification noti = builder.build();\nNotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n//just set the mId to 1, because we don't care about it in this case\nmNotificationManager.notify(1, noti);\n",[56,291,292,297,302,307,312,317,322,327,332,337,342,347,352],{"__ignoreMap":54},[59,293,294],{"class":61,"line":62},[59,295,296],{},"NotificationCompat.Builder builder = new NotificationCompat.Builder(\n",[59,298,299],{"class":61,"line":69},[59,300,301],{}," context);\n",[59,303,304],{"class":61,"line":75},[59,305,306],{},"builder.setContentIntent(pendingIntent);\n",[59,308,309],{"class":61,"line":81},[59,310,311],{},"builder.setAutoCancel(true);\n",[59,313,314],{"class":61,"line":87},[59,315,316],{},"builder.setSmallIcon(R.drawable.ic_launcher);\n",[59,318,319],{"class":61,"line":93},[59,320,321],{},"//this is added on the server side\n",[59,323,324],{"class":61,"line":99},[59,325,326],{},"String text = intent.getStringExtra(\"text\");\n",[59,328,329],{"class":61,"line":105},[59,330,331],{},"builder.setContentText(text);\n",[59,333,334],{"class":61,"line":111},[59,335,336],{},"builder.setContentTitle(\"New message from the cloud!\");\n",[59,338,339],{"class":61,"line":117},[59,340,341],{},"Notification noti = builder.build();\n",[59,343,344],{"class":61,"line":123},[59,345,346],{},"NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n",[59,348,349],{"class":61,"line":129},[59,350,351],{},"//just set the mId to 1, because we don't care about it in this case\n",[59,353,354],{"class":61,"line":135},[59,355,356],{},"mNotificationManager.notify(1, noti);\n",[18,358,359],{},"That’ it with the GCMIntentService.",[18,361,362],{},"Now we let the app register itself with GCM in our MainActivity, which is fairly easy:",[49,364,366],{"className":206,"code":365,"language":208,"meta":54,"style":54},"//set your senderId from the API here!\n private static final String SENDER_ID = \"1234567890\";\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n GCMRegistrar.checkDevice(this);\n GCMRegistrar.checkManifest(this);\n final String regId = GCMRegistrar.getRegistrationId(this);\n // if we don't have a regId yet, register at gcm\n if (regId.equals(\"\")) {\n GCMRegistrar.register(this, SENDER_ID);\n Toast.makeText(getApplicationContext(), \"Registered GCM!\", Toast.LENGTH_LONG).show();\n // just log the registrationId for this test case.\n Log.i(this.getClass().getName(), \"id: \" + GCMRegistrar.getRegistrationId(this));\n } else {\n Log.i(this.getClass().getName(), \"Already registered\");\n Toast.makeText(getApplicationContext(), \"Already registered at GCM!\", Toast.LENGTH_LONG).show();\n Log.i(this.getClass().getName(), \"id: \" + GCMRegistrar.getRegistrationId(this));\n }\n}\n",[56,367,368,373,378,383,388,393,398,403,408,413,418,423,428,433,439,445,451,456,462],{"__ignoreMap":54},[59,369,370],{"class":61,"line":62},[59,371,372],{},"//set your senderId from the API here!\n",[59,374,375],{"class":61,"line":69},[59,376,377],{}," private static final String SENDER_ID = \"1234567890\";\n",[59,379,380],{"class":61,"line":75},[59,381,382],{},"@Override\n",[59,384,385],{"class":61,"line":81},[59,386,387],{},"protected void onCreate(Bundle savedInstanceState) {\n",[59,389,390],{"class":61,"line":87},[59,391,392],{}," GCMRegistrar.checkDevice(this);\n",[59,394,395],{"class":61,"line":93},[59,396,397],{}," GCMRegistrar.checkManifest(this);\n",[59,399,400],{"class":61,"line":99},[59,401,402],{}," final String regId = GCMRegistrar.getRegistrationId(this);\n",[59,404,405],{"class":61,"line":105},[59,406,407],{}," // if we don't have a regId yet, register at gcm\n",[59,409,410],{"class":61,"line":111},[59,411,412],{}," if (regId.equals(\"\")) {\n",[59,414,415],{"class":61,"line":117},[59,416,417],{}," GCMRegistrar.register(this, SENDER_ID);\n",[59,419,420],{"class":61,"line":123},[59,421,422],{}," Toast.makeText(getApplicationContext(), \"Registered GCM!\", Toast.LENGTH_LONG).show();\n",[59,424,425],{"class":61,"line":129},[59,426,427],{}," // just log the registrationId for this test case.\n",[59,429,430],{"class":61,"line":135},[59,431,432],{}," Log.i(this.getClass().getName(), \"id: \" + GCMRegistrar.getRegistrationId(this));\n",[59,434,436],{"class":61,"line":435},14,[59,437,438],{}," } else {\n",[59,440,442],{"class":61,"line":441},15,[59,443,444],{}," Log.i(this.getClass().getName(), \"Already registered\");\n",[59,446,448],{"class":61,"line":447},16,[59,449,450],{}," Toast.makeText(getApplicationContext(), \"Already registered at GCM!\", Toast.LENGTH_LONG).show();\n",[59,452,454],{"class":61,"line":453},17,[59,455,432],{},[59,457,459],{"class":61,"line":458},18,[59,460,461],{}," }\n",[59,463,465],{"class":61,"line":464},19,[59,466,253],{},[18,468,469],{},"Don’t forget to replace the SENDER_ID with yours!",[18,471,472],{},"I haven’t implemented a way to let the server know the registrationId, because reading it from the log seemed sufficient\nfor me in this case.",[18,474,475],{},"With this, we finished our small app and can begin implementing the server part.",[38,477,479],{"id":478},"the-web-application","The Web Application",[18,481,482],{},"For the Web Application, I created a maven web project with spring-webmvc and named it ‘GCMTestServer’. I’ll leave out\nthe config stuff for now, as everyone can use his/her favorite stack for this. The full sources with the configs are\nattached at the end of the blogpost.",[18,484,485,486,490],{},"Instead of just copying the GCM server library into the project, I searched a bit and found someone, who created a\nrepository for\nit. (",[25,487,488],{"href":488,"rel":489},"https://github.com/slorber/gcm-server-repository",[29],")",[18,492,493],{},"We start with creating the Sender class, which isn’t that hard either.",[49,495,497],{"className":206,"code":496,"language":208,"meta":54,"style":54},"public class GCMSender {\n public String apiKey = null;\n public GCMSender(String apiKey) {\n this.apiKey = apiKey;\n }\n public String send(String text, String id) throws IOException {\n Sender sender = new Sender(apiKey);\n Builder builder = new Message.Builder();\n builder.addData(\"text\", text);\n Result result = sender.send(builder.build(), id, 5);\n if (result.getMessageId() != null) {\n String canonicalRegId = result.getCanonicalRegistrationId();\n if (canonicalRegId != null) {\n // same device has more than on registration ID: update database\n return \"same device has more than on registration ID: update database\";\n }\n } else {\n String error = result.getErrorCodeName();\n if (error.equals(Constants.ERROR_NOT_REGISTERED)) {\n // application has been removed from device - unregister database\n return \"application has been removed from device - unregister database\";\n }\n }\n return null;\n }\n}\n",[56,498,499,504,509,514,519,524,529,534,539,544,549,554,559,564,569,574,579,584,589,594,600,606,611,616,622,627],{"__ignoreMap":54},[59,500,501],{"class":61,"line":62},[59,502,503],{},"public class GCMSender {\n",[59,505,506],{"class":61,"line":69},[59,507,508],{}," public String apiKey = null;\n",[59,510,511],{"class":61,"line":75},[59,512,513],{}," public GCMSender(String apiKey) {\n",[59,515,516],{"class":61,"line":81},[59,517,518],{}," this.apiKey = apiKey;\n",[59,520,521],{"class":61,"line":87},[59,522,523],{}," }\n",[59,525,526],{"class":61,"line":93},[59,527,528],{}," public String send(String text, String id) throws IOException {\n",[59,530,531],{"class":61,"line":99},[59,532,533],{}," Sender sender = new Sender(apiKey);\n",[59,535,536],{"class":61,"line":105},[59,537,538],{}," Builder builder = new Message.Builder();\n",[59,540,541],{"class":61,"line":111},[59,542,543],{}," builder.addData(\"text\", text);\n",[59,545,546],{"class":61,"line":117},[59,547,548],{}," Result result = sender.send(builder.build(), id, 5);\n",[59,550,551],{"class":61,"line":123},[59,552,553],{}," if (result.getMessageId() != null) {\n",[59,555,556],{"class":61,"line":129},[59,557,558],{}," String canonicalRegId = result.getCanonicalRegistrationId();\n",[59,560,561],{"class":61,"line":135},[59,562,563],{}," if (canonicalRegId != null) {\n",[59,565,566],{"class":61,"line":435},[59,567,568],{}," // same device has more than on registration ID: update database\n",[59,570,571],{"class":61,"line":441},[59,572,573],{}," return \"same device has more than on registration ID: update database\";\n",[59,575,576],{"class":61,"line":447},[59,577,578],{}," }\n",[59,580,581],{"class":61,"line":453},[59,582,583],{}," } else {\n",[59,585,586],{"class":61,"line":458},[59,587,588],{}," String error = result.getErrorCodeName();\n",[59,590,591],{"class":61,"line":464},[59,592,593],{}," if (error.equals(Constants.ERROR_NOT_REGISTERED)) {\n",[59,595,597],{"class":61,"line":596},20,[59,598,599],{}," // application has been removed from device - unregister database\n",[59,601,603],{"class":61,"line":602},21,[59,604,605],{}," return \"application has been removed from device - unregister database\";\n",[59,607,609],{"class":61,"line":608},22,[59,610,578],{},[59,612,614],{"class":61,"line":613},23,[59,615,461],{},[59,617,619],{"class":61,"line":618},24,[59,620,621],{}," return null;\n",[59,623,625],{"class":61,"line":624},25,[59,626,523],{},[59,628,630],{"class":61,"line":629},26,[59,631,253],{},[18,633,634],{},"To send messages from the server, I created a small jsp page where I can enter the text and the RegistrationId of the\nuser to send the message to:",[49,636,640],{"className":637,"code":638,"language":639,"meta":54,"style":54},"language-html shiki shiki-themes github-light github-dark","\u003C%@ taglib prefix=\"c\" uri=\"http://java.sun.com/jsp/jstl/core\" %> \u003C%@page\ncontentType=\"text/html\" pageEncoding=\"UTF-8\"%>\n\u003C!DOCTYPE html>\n\u003Chtml>\n \u003Chead>\n \u003Cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n \u003Clink\n rel=\"stylesheet\"\n type=\"text/css\"\n href=\"/GCMTestServer/frontend_resources/style.css\"\n media=\"screen\"\n />\n \u003Ctitle>GCM Sender\u003C/title>\n \u003C/head>\n \u003Cbody>\n \u003Ch1>GCM Sender\u003C/h1>\n \u003Cc:if test=\"${success == true}\">\n \u003Cdiv class=\"success\">sending successful!\u003C/div>\n \u003C/c:if>\n \u003Cc:if test=\"${error == true}\">\n \u003Cdiv class=\"error\">\n Error at sending!\n \u003Cp>${errormessage}\u003C/p>\n \u003C/div>\n \u003C/c:if>\n \u003Cform method=\"POST\">\n \u003Clabel for=\"text\">Text\u003C/label\n >\u003Cinput name=\"text\" id=\"text\" type=\"text\" />\u003Cbr />\n \u003Clabel for=\"id\">Registration-Id\u003C/label\n >\u003Cinput name=\"id\" id=\"id\" type=\"text\" />\u003Cbr />\n \u003Cinput type=\"submit\" />\n \u003C/form>\n \u003C/body>\n\u003C/html>\n","html",[56,641,642,657,662,678,686,696,725,732,742,752,762,772,777,791,800,809,821,838,861,870,885,900,905,919,928,936,953,975,1013,1032,1063,1079,1088,1097],{"__ignoreMap":54},[59,643,644,648,652,654],{"class":61,"line":62},[59,645,647],{"class":646},"s7hpK","\u003C",[59,649,651],{"class":650},"sVt8B","%@ taglib prefix=\"c\" uri=\"http://java.sun.com/jsp/jstl/core\" %> ",[59,653,647],{"class":646},[59,655,656],{"class":650},"%@page\n",[59,658,659],{"class":61,"line":69},[59,660,661],{"class":650},"contentType=\"text/html\" pageEncoding=\"UTF-8\"%>\n",[59,663,664,667,671,675],{"class":61,"line":75},[59,665,666],{"class":650},"\u003C!",[59,668,670],{"class":669},"s9eBZ","DOCTYPE",[59,672,674],{"class":673},"sScJk"," html",[59,676,677],{"class":650},">\n",[59,679,680,682,684],{"class":61,"line":81},[59,681,647],{"class":650},[59,683,639],{"class":669},[59,685,677],{"class":650},[59,687,688,691,694],{"class":61,"line":87},[59,689,690],{"class":650}," \u003C",[59,692,693],{"class":669},"head",[59,695,677],{"class":650},[59,697,698,701,704,707,710,714,717,719,722],{"class":61,"line":93},[59,699,700],{"class":650}," \u003C",[59,702,703],{"class":669},"meta",[59,705,706],{"class":673}," http-equiv",[59,708,709],{"class":650},"=",[59,711,713],{"class":712},"sZZnC","\"Content-Type\"",[59,715,716],{"class":673}," content",[59,718,709],{"class":650},[59,720,721],{"class":712},"\"text/html; charset=UTF-8\"",[59,723,724],{"class":650}," />\n",[59,726,727,729],{"class":61,"line":99},[59,728,700],{"class":650},[59,730,731],{"class":669},"link\n",[59,733,734,737,739],{"class":61,"line":105},[59,735,736],{"class":673}," rel",[59,738,709],{"class":650},[59,740,741],{"class":712},"\"stylesheet\"\n",[59,743,744,747,749],{"class":61,"line":111},[59,745,746],{"class":673}," type",[59,748,709],{"class":650},[59,750,751],{"class":712},"\"text/css\"\n",[59,753,754,757,759],{"class":61,"line":117},[59,755,756],{"class":673}," href",[59,758,709],{"class":650},[59,760,761],{"class":712},"\"/GCMTestServer/frontend_resources/style.css\"\n",[59,763,764,767,769],{"class":61,"line":123},[59,765,766],{"class":673}," media",[59,768,709],{"class":650},[59,770,771],{"class":712},"\"screen\"\n",[59,773,774],{"class":61,"line":129},[59,775,776],{"class":650}," />\n",[59,778,779,781,784,787,789],{"class":61,"line":135},[59,780,700],{"class":650},[59,782,783],{"class":669},"title",[59,785,786],{"class":650},">GCM Sender\u003C/",[59,788,783],{"class":669},[59,790,677],{"class":650},[59,792,793,796,798],{"class":61,"line":435},[59,794,795],{"class":650}," \u003C/",[59,797,693],{"class":669},[59,799,677],{"class":650},[59,801,802,804,807],{"class":61,"line":441},[59,803,690],{"class":650},[59,805,806],{"class":669},"body",[59,808,677],{"class":650},[59,810,811,813,815,817,819],{"class":61,"line":447},[59,812,700],{"class":650},[59,814,14],{"class":669},[59,816,786],{"class":650},[59,818,14],{"class":669},[59,820,677],{"class":650},[59,822,823,825,828,831,833,836],{"class":61,"line":453},[59,824,700],{"class":650},[59,826,827],{"class":646},"c:if",[59,829,830],{"class":673}," test",[59,832,709],{"class":650},[59,834,835],{"class":712},"\"${success == true}\"",[59,837,677],{"class":650},[59,839,840,843,846,849,851,854,857,859],{"class":61,"line":458},[59,841,842],{"class":650}," \u003C",[59,844,845],{"class":669},"div",[59,847,848],{"class":673}," class",[59,850,709],{"class":650},[59,852,853],{"class":712},"\"success\"",[59,855,856],{"class":650},">sending successful!\u003C/",[59,858,845],{"class":669},[59,860,677],{"class":650},[59,862,863,866,868],{"class":61,"line":464},[59,864,865],{"class":650}," \u003C/",[59,867,827],{"class":646},[59,869,677],{"class":650},[59,871,872,874,876,878,880,883],{"class":61,"line":596},[59,873,700],{"class":650},[59,875,827],{"class":646},[59,877,830],{"class":673},[59,879,709],{"class":650},[59,881,882],{"class":712},"\"${error == true}\"",[59,884,677],{"class":650},[59,886,887,889,891,893,895,898],{"class":61,"line":602},[59,888,842],{"class":650},[59,890,845],{"class":669},[59,892,848],{"class":673},[59,894,709],{"class":650},[59,896,897],{"class":712},"\"error\"",[59,899,677],{"class":650},[59,901,902],{"class":61,"line":608},[59,903,904],{"class":650}," Error at sending!\n",[59,906,907,910,912,915,917],{"class":61,"line":613},[59,908,909],{"class":650}," \u003C",[59,911,18],{"class":669},[59,913,914],{"class":650},">${errormessage}\u003C/",[59,916,18],{"class":669},[59,918,677],{"class":650},[59,920,921,924,926],{"class":61,"line":618},[59,922,923],{"class":650}," \u003C/",[59,925,845],{"class":669},[59,927,677],{"class":650},[59,929,930,932,934],{"class":61,"line":624},[59,931,865],{"class":650},[59,933,827],{"class":646},[59,935,677],{"class":650},[59,937,938,940,943,946,948,951],{"class":61,"line":629},[59,939,700],{"class":650},[59,941,942],{"class":669},"form",[59,944,945],{"class":673}," method",[59,947,709],{"class":650},[59,949,950],{"class":712},"\"POST\"",[59,952,677],{"class":650},[59,954,956,958,961,964,966,969,972],{"class":61,"line":955},27,[59,957,842],{"class":650},[59,959,960],{"class":669},"label",[59,962,963],{"class":673}," for",[59,965,709],{"class":650},[59,967,968],{"class":712},"\"text\"",[59,970,971],{"class":650},">Text\u003C/",[59,973,974],{"class":669},"label\n",[59,976,978,981,984,987,989,991,994,996,998,1001,1003,1005,1008,1011],{"class":61,"line":977},28,[59,979,980],{"class":650}," >\u003C",[59,982,983],{"class":669},"input",[59,985,986],{"class":673}," name",[59,988,709],{"class":650},[59,990,968],{"class":712},[59,992,993],{"class":673}," id",[59,995,709],{"class":650},[59,997,968],{"class":712},[59,999,1000],{"class":673}," type",[59,1002,709],{"class":650},[59,1004,968],{"class":712},[59,1006,1007],{"class":650}," />\u003C",[59,1009,1010],{"class":669},"br",[59,1012,724],{"class":650},[59,1014,1016,1018,1020,1022,1024,1027,1030],{"class":61,"line":1015},29,[59,1017,842],{"class":650},[59,1019,960],{"class":669},[59,1021,963],{"class":673},[59,1023,709],{"class":650},[59,1025,1026],{"class":712},"\"id\"",[59,1028,1029],{"class":650},">Registration-Id\u003C/",[59,1031,974],{"class":669},[59,1033,1035,1037,1039,1041,1043,1045,1047,1049,1051,1053,1055,1057,1059,1061],{"class":61,"line":1034},30,[59,1036,980],{"class":650},[59,1038,983],{"class":669},[59,1040,986],{"class":673},[59,1042,709],{"class":650},[59,1044,1026],{"class":712},[59,1046,993],{"class":673},[59,1048,709],{"class":650},[59,1050,1026],{"class":712},[59,1052,1000],{"class":673},[59,1054,709],{"class":650},[59,1056,968],{"class":712},[59,1058,1007],{"class":650},[59,1060,1010],{"class":669},[59,1062,724],{"class":650},[59,1064,1066,1068,1070,1072,1074,1077],{"class":61,"line":1065},31,[59,1067,842],{"class":650},[59,1069,983],{"class":669},[59,1071,1000],{"class":673},[59,1073,709],{"class":650},[59,1075,1076],{"class":712},"\"submit\"",[59,1078,724],{"class":650},[59,1080,1082,1084,1086],{"class":61,"line":1081},32,[59,1083,865],{"class":650},[59,1085,942],{"class":669},[59,1087,677],{"class":650},[59,1089,1091,1093,1095],{"class":61,"line":1090},33,[59,1092,795],{"class":650},[59,1094,806],{"class":669},[59,1096,677],{"class":650},[59,1098,1100,1103,1105],{"class":61,"line":1099},34,[59,1101,1102],{"class":650},"\u003C/",[59,1104,639],{"class":669},[59,1106,677],{"class":650},[18,1108,1109],{},"In the corresponding Controller to process the request, send the message:",[49,1111,1113],{"className":206,"code":1112,"language":208,"meta":54,"style":54}," @RequestMapping(value = \"send\", method = RequestMethod.POST)\n public String send(Model model,\n @RequestParam(\"text\") String text,\n @RequestParam(\"id\") String id) {\n String error = null;\n try {\n error = gcmSender.send(text, id);\n } catch (IOException ex) {\n model.addAttribute(\"error\", true);\n model.addAttribute(\"errormessage\", ex.getMessage());\n }\n if (error == null) {\n model.addAttribute(\"success\", true);\n } else {\n model.addAttribute(\"error\", true);\n model.addAttribute(\"errormessage\", error);\n }\n return \"sender\";\n }\n",[56,1114,1115,1120,1125,1130,1135,1140,1145,1150,1155,1160,1165,1170,1175,1180,1185,1189,1194,1198,1203],{"__ignoreMap":54},[59,1116,1117],{"class":61,"line":62},[59,1118,1119],{}," @RequestMapping(value = \"send\", method = RequestMethod.POST)\n",[59,1121,1122],{"class":61,"line":69},[59,1123,1124],{}," public String send(Model model,\n",[59,1126,1127],{"class":61,"line":75},[59,1128,1129],{}," @RequestParam(\"text\") String text,\n",[59,1131,1132],{"class":61,"line":81},[59,1133,1134],{}," @RequestParam(\"id\") String id) {\n",[59,1136,1137],{"class":61,"line":87},[59,1138,1139],{}," String error = null;\n",[59,1141,1142],{"class":61,"line":93},[59,1143,1144],{}," try {\n",[59,1146,1147],{"class":61,"line":99},[59,1148,1149],{}," error = gcmSender.send(text, id);\n",[59,1151,1152],{"class":61,"line":105},[59,1153,1154],{}," } catch (IOException ex) {\n",[59,1156,1157],{"class":61,"line":111},[59,1158,1159],{}," model.addAttribute(\"error\", true);\n",[59,1161,1162],{"class":61,"line":117},[59,1163,1164],{}," model.addAttribute(\"errormessage\", ex.getMessage());\n",[59,1166,1167],{"class":61,"line":123},[59,1168,1169],{}," }\n",[59,1171,1172],{"class":61,"line":129},[59,1173,1174],{}," if (error == null) {\n",[59,1176,1177],{"class":61,"line":135},[59,1178,1179],{}," model.addAttribute(\"success\", true);\n",[59,1181,1182],{"class":61,"line":435},[59,1183,1184],{}," } else {\n",[59,1186,1187],{"class":61,"line":441},[59,1188,1159],{},[59,1190,1191],{"class":61,"line":447},[59,1192,1193],{}," model.addAttribute(\"errormessage\", error);\n",[59,1195,1196],{"class":61,"line":453},[59,1197,1169],{},[59,1199,1200],{"class":61,"line":458},[59,1201,1202],{}," return \"sender\";\n",[59,1204,1205],{"class":61,"line":464},[59,1206,248],{},[18,1208,1209],{},"Now we are ready to test it!",[18,1211,1212],{},"Start the app, copy the RegistrationId from the Logs, start the Server, enter the RegistrationId and a small text, and\nthere you go:",[18,1214,1215],{},[1216,1217],"img",{"alt":1218,"src":1219},"\"notification\"","https://media.synyx.de/uploads//2012/12/notification-300x221.jpg",[18,1221,1222],{},"To get a better understanding, you can also read the rest of the starting guide and the other documentation.",[18,1224,1225],{},"All together, it’s really easy to use the GCM libraries and the messages are beeing sent to the user very fast (around\none second for me). I haven’t tried to use it in a greater context with more users yet, but I don’t think google will\nfail on this behalf 😛",[18,1227,1228,1229],{},"As promised, here are the full sources:",[25,1230,1233],{"href":1231,"rel":1232},"https://media.synyx.de/uploads//2012/12/CloudMessageTest.zip",[29],"CloudMessageTest",[1235,1236,1237],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7hpK, html code.shiki .s7hpK{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":54,"searchDepth":69,"depth":69,"links":1239},[1240,1241],{"id":40,"depth":69,"text":41},{"id":478,"depth":69,"text":479},[1243,1244],"mobile-blog","tutorial","2013-01-08T08:21:24","md","https://synyx.de/blog/a-small-look-into-google-cloud-messages/",{},"/blog/a-small-look-into-google-cloud-messages",{"title":7,"description":20},{"loc":1249},"blog/a-small-look-into-google-cloud-messages",[1254,1255,1256,1257,1258,1259,1260],"android","cloud","gcm","google-cloud","messages","messaging","push-notification","Within the scope of some Android R&D I took a look at Google’s Cloud Message Service, GCM. Well, the starter guide at http://developer.android.com/google/gcm/gs.html is almost all you need to get started,…","OAaYVJ_tCf4EjtyhcR8UEkVStNcR69sWPts5WylIFqc",{"id":1264,"title":1265,"author":1266,"body":1268,"category":1281,"date":1283,"description":54,"extension":1246,"link":1284,"meta":1285,"navigation":65,"path":1286,"seo":1287,"sitemap":1288,"slug":1272,"stem":1289,"tags":1290,"teaser":1296,"__hash__":1297},"blog/blog/apn-device-tokens.md","APN Device Tokens",[1267],"linsin",{"type":11,"value":1269,"toc":1279},[1270,1273],[14,1271,1265],{"id":1272},"apn-device-tokens",[18,1274,1275],{},[1216,1276],{"alt":1277,"src":1278},"I Think I Spider","https://media.synyx.de/uploads//2010/07/512px.png",{"title":54,"searchDepth":69,"depth":69,"links":1280},[],[1243,1282,1244],"our-apps","2010-09-14T06:46:26","https://synyx.de/blog/apn-device-tokens/",{},"/blog/apn-device-tokens",{"title":1265,"description":54},{"loc":1286},"blog/apn-device-tokens",[1291,1292,1293,1294,1295],"apn","apple","ipad","iphone","push-notifications","When you enable Apple Push Notifications (APN) for your App, your device generates a unique device token and pass it to the didRegisterForRemoteNotificationsWithDeviceToken method in your App delegate. Usually, you’ll…","YzPTSVkCYS0h7Th05NS5TTxezfHGC5mPlgIce5yoMBA",{"id":1299,"title":1300,"author":1301,"body":1302,"category":1633,"date":1634,"description":1635,"extension":1246,"link":1636,"meta":1637,"navigation":65,"path":1638,"seo":1639,"sitemap":1641,"slug":1306,"stem":1642,"tags":1643,"teaser":1644,"__hash__":1645},"blog/blog/sending-apple-push-notifications-with-notnoops-java-apns-library.md","Sending Apple Push Notifications with notnoop's java-apns library",[9],{"type":11,"value":1303,"toc":1631},[1304,1307,1322,1330,1333,1340,1343,1625,1628],[14,1305,1300],{"id":1306},"sending-apple-push-notifications-with-notnoops-java-apns-library",[18,1308,1309,1310,1315,1316,1321],{},"If you need to send apple push notifications to your users, like we do in\na ",[25,1311,1314],{"href":1312,"rel":1313},"http://mobile.synyx.de/2010/07/i-think-i-spider/",[29],"secret project"," mentioned earlier this\nweek, ",[25,1317,1320],{"href":1318,"rel":1319},"http://github.com/notnoop/java-apns",[29],"notnoop’s java-apns library"," is a good choice, because its really simple to\nuse and saves you a lot of work.",[18,1323,1324,1325,490],{},"(I presume that you already know how to get the Tokens of your users and already have a certificate for the push\nnotifications, I only show you how easy the server part can be with this library. If you don’t know, read this\nfirst: ",[25,1326,1329],{"href":1327,"rel":1328},"http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ApplePushService/ApplePushService.html",[29],"Apple Push Service",[18,1331,1332],{},"First you have to download the library (or add it in your maven dependencies):",[18,1334,1335],{},[25,1336,1339],{"href":1337,"rel":1338},"http://github.com/notnoop/java-apns/tree/",[29],"java-apns",[18,1341,1342],{},"The programming part isn’t that much so here’s how you do it:",[49,1344,1346],{"className":206,"code":1345,"language":208,"meta":54,"style":54},"\npublic void pushMessage() {\n ApnsService service = null;\n try {\n // get the certificate\n InputStream certStream = this.getClass().getClassLoader().getResourceAsStream(\"your_certificate.p12\");\n service = APNS.newService().withCert(certStream, \"your_cert_password\").withSandboxDestination().build();\n // or\n // service = APNS.newService().withCert(certStream,\n // \"your_cert_password\").withProductionDestination().build();\n service.start();\n // You have to delete the devices from you list that no longer\n //have the app installed, see method below\n deleteInactiveDevices(service);\n // read your user list\n List\u003CUser> userList = userDao.readUsers();\n for (User user : userList) {\n try {\n // we had a daily update here, so we need to know how many\n //days the user hasn't started the app\n // so that we get the number of updates to display it as the badge.\n int days = (int) ((System.currentTimeMillis() - user.getLastUpdate()) / 1000 / 60 / 60 / 24);\n PayloadBuilder payloadBuilder = APNS.newPayload();\n payloadBuilder = payloadBuilder.badge(days).alertBody(\"some message you want to send here\");\n // check if the message is too long (it won't be sent if it is)\n //and trim it if it is.\n if (payloadBuilder.isTooLong()) {\n payloadBuilder = payloadBuilder.shrinkBody();\n }\n String payload = payloadBuilder.build();\n String token = user.getToken();\n service.push(token, payload);\n } catch (Exception ex) {\n // some logging stuff\n }\n }\n } catch (Exception ex) {\n // more logging\n } finally {\n // check if the service was successfull initialized and stop it here, if it was\n if (service != null) {\n service.stop();\n }\n }\n }\n private void deleteInactiveDevices(ApnsService service) {\n // get the list of the devices that no longer have your app installed from apple\n //ignore the =\"\" after Date here, it's a bug...\n Map\u003CString, Date> inactiveDevices = service.getInactiveDevices();\n for (String deviceToken : inactiveDevices.keySet()) {\n userDao.deleteByDeviceId(deviceToken);\n }\n }\n\n",[56,1347,1348,1352,1357,1362,1366,1371,1376,1381,1386,1391,1396,1401,1406,1411,1416,1421,1426,1431,1436,1441,1446,1451,1456,1461,1466,1471,1476,1481,1486,1491,1496,1501,1506,1511,1516,1522,1528,1534,1540,1546,1552,1558,1564,1569,1574,1579,1585,1591,1597,1603,1609,1615,1620],{"__ignoreMap":54},[59,1349,1350],{"class":61,"line":62},[59,1351,66],{"emptyLinePlaceholder":65},[59,1353,1354],{"class":61,"line":69},[59,1355,1356],{},"public void pushMessage() {\n",[59,1358,1359],{"class":61,"line":75},[59,1360,1361],{}," ApnsService service = null;\n",[59,1363,1364],{"class":61,"line":81},[59,1365,1144],{},[59,1367,1368],{"class":61,"line":87},[59,1369,1370],{}," // get the certificate\n",[59,1372,1373],{"class":61,"line":93},[59,1374,1375],{}," InputStream certStream = this.getClass().getClassLoader().getResourceAsStream(\"your_certificate.p12\");\n",[59,1377,1378],{"class":61,"line":99},[59,1379,1380],{}," service = APNS.newService().withCert(certStream, \"your_cert_password\").withSandboxDestination().build();\n",[59,1382,1383],{"class":61,"line":105},[59,1384,1385],{}," // or\n",[59,1387,1388],{"class":61,"line":111},[59,1389,1390],{}," // service = APNS.newService().withCert(certStream,\n",[59,1392,1393],{"class":61,"line":117},[59,1394,1395],{}," // \"your_cert_password\").withProductionDestination().build();\n",[59,1397,1398],{"class":61,"line":123},[59,1399,1400],{}," service.start();\n",[59,1402,1403],{"class":61,"line":129},[59,1404,1405],{}," // You have to delete the devices from you list that no longer\n",[59,1407,1408],{"class":61,"line":135},[59,1409,1410],{}," //have the app installed, see method below\n",[59,1412,1413],{"class":61,"line":435},[59,1414,1415],{}," deleteInactiveDevices(service);\n",[59,1417,1418],{"class":61,"line":441},[59,1419,1420],{}," // read your user list\n",[59,1422,1423],{"class":61,"line":447},[59,1424,1425],{}," List\u003CUser> userList = userDao.readUsers();\n",[59,1427,1428],{"class":61,"line":453},[59,1429,1430],{}," for (User user : userList) {\n",[59,1432,1433],{"class":61,"line":458},[59,1434,1435],{}," try {\n",[59,1437,1438],{"class":61,"line":464},[59,1439,1440],{}," // we had a daily update here, so we need to know how many\n",[59,1442,1443],{"class":61,"line":596},[59,1444,1445],{}," //days the user hasn't started the app\n",[59,1447,1448],{"class":61,"line":602},[59,1449,1450],{}," // so that we get the number of updates to display it as the badge.\n",[59,1452,1453],{"class":61,"line":608},[59,1454,1455],{}," int days = (int) ((System.currentTimeMillis() - user.getLastUpdate()) / 1000 / 60 / 60 / 24);\n",[59,1457,1458],{"class":61,"line":613},[59,1459,1460],{}," PayloadBuilder payloadBuilder = APNS.newPayload();\n",[59,1462,1463],{"class":61,"line":618},[59,1464,1465],{}," payloadBuilder = payloadBuilder.badge(days).alertBody(\"some message you want to send here\");\n",[59,1467,1468],{"class":61,"line":624},[59,1469,1470],{}," // check if the message is too long (it won't be sent if it is)\n",[59,1472,1473],{"class":61,"line":629},[59,1474,1475],{}," //and trim it if it is.\n",[59,1477,1478],{"class":61,"line":955},[59,1479,1480],{}," if (payloadBuilder.isTooLong()) {\n",[59,1482,1483],{"class":61,"line":977},[59,1484,1485],{}," payloadBuilder = payloadBuilder.shrinkBody();\n",[59,1487,1488],{"class":61,"line":1015},[59,1489,1490],{}," }\n",[59,1492,1493],{"class":61,"line":1034},[59,1494,1495],{}," String payload = payloadBuilder.build();\n",[59,1497,1498],{"class":61,"line":1065},[59,1499,1500],{}," String token = user.getToken();\n",[59,1502,1503],{"class":61,"line":1081},[59,1504,1505],{}," service.push(token, payload);\n",[59,1507,1508],{"class":61,"line":1090},[59,1509,1510],{}," } catch (Exception ex) {\n",[59,1512,1513],{"class":61,"line":1099},[59,1514,1515],{}," // some logging stuff\n",[59,1517,1519],{"class":61,"line":1518},35,[59,1520,1521],{}," }\n",[59,1523,1525],{"class":61,"line":1524},36,[59,1526,1527],{}," }\n",[59,1529,1531],{"class":61,"line":1530},37,[59,1532,1533],{}," } catch (Exception ex) {\n",[59,1535,1537],{"class":61,"line":1536},38,[59,1538,1539],{}," // more logging\n",[59,1541,1543],{"class":61,"line":1542},39,[59,1544,1545],{}," } finally {\n",[59,1547,1549],{"class":61,"line":1548},40,[59,1550,1551],{}," // check if the service was successfull initialized and stop it here, if it was\n",[59,1553,1555],{"class":61,"line":1554},41,[59,1556,1557],{}," if (service != null) {\n",[59,1559,1561],{"class":61,"line":1560},42,[59,1562,1563],{}," service.stop();\n",[59,1565,1567],{"class":61,"line":1566},43,[59,1568,1527],{},[59,1570,1572],{"class":61,"line":1571},44,[59,1573,1169],{},[59,1575,1577],{"class":61,"line":1576},45,[59,1578,248],{},[59,1580,1582],{"class":61,"line":1581},46,[59,1583,1584],{}," private void deleteInactiveDevices(ApnsService service) {\n",[59,1586,1588],{"class":61,"line":1587},47,[59,1589,1590],{}," // get the list of the devices that no longer have your app installed from apple\n",[59,1592,1594],{"class":61,"line":1593},48,[59,1595,1596],{}," //ignore the =\"\" after Date here, it's a bug...\n",[59,1598,1600],{"class":61,"line":1599},49,[59,1601,1602],{}," Map\u003CString, Date> inactiveDevices = service.getInactiveDevices();\n",[59,1604,1606],{"class":61,"line":1605},50,[59,1607,1608],{}," for (String deviceToken : inactiveDevices.keySet()) {\n",[59,1610,1612],{"class":61,"line":1611},51,[59,1613,1614],{}," userDao.deleteByDeviceId(deviceToken);\n",[59,1616,1618],{"class":61,"line":1617},52,[59,1619,1169],{},[59,1621,1623],{"class":61,"line":1622},53,[59,1624,248],{},[18,1626,1627],{},"Now wasn’t that an easy one this time?",[1235,1629,1630],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":54,"searchDepth":69,"depth":69,"links":1632},[],[1243],"2010-07-27T07:00:38","If you need to send apple push notifications to your users, like we do in\\na secret project mentioned earlier this\\nweek, notnoop’s java-apns library is a good choice, because its really simple to\\nuse and saves you a lot of work.","https://synyx.de/blog/sending-apple-push-notifications-with-notnoops-java-apns-library/",{},"/blog/sending-apple-push-notifications-with-notnoops-java-apns-library",{"title":1300,"description":1640},"If you need to send apple push notifications to your users, like we do in\na secret project mentioned earlier this\nweek, notnoop’s java-apns library is a good choice, because its really simple to\nuse and saves you a lot of work.",{"loc":1638},"blog/sending-apple-push-notifications-with-notnoops-java-apns-library",[1291,1292,1294,1260],"If you need to send apple push notifications to your users, like we do in a secret project mentioned earlier this week, notnoop’s java-apns library is a good choice, because…","xShL0XLfGwd4K-DK4dv0mRZDSMwqR2cAureM6eI72FQ",[1647,1650,1653,1656,1659,1662,1665,1668,1671,1674,1677,1680,1683,1686,1689,1692,1695,1698,1701,1704,1707,1710,1712,1715,1718,1721,1724,1726,1729,1732,1735,1738,1741,1744,1747,1750,1753,1756,1759,1762,1765,1768,1771,1774,1777,1780,1783,1786,1789,1792,1795,1798,1801,1804,1807,1810,1813,1816,1819,1822,1825,1828,1831,1833,1836,1839,1842,1845,1848,1851,1854,1857,1860,1863,1865,1868,1871,1874,1877,1880,1883,1886,1889,1892,1895,1898,1901,1904,1907,1910,1913,1916,1919,1922,1925,1928,1931,1934,1937,1939,1942,1945,1948,1951,1953,1956,1959,1962,1965,1968,1971,1974,1977,1980,1983,1986,1989,1992,1995,1998,2001,2004,2007,2010,2013,2016,2019,2022,2025,2028,2030,2033,2036,2039,2042,2045,2048,2051,2054,2057,2060,2063],{"slug":1648,"name":1649},"abel","Jennifer Abel",{"slug":1651,"name":1652},"allmendinger","Otto Allmendinger",{"slug":1654,"name":1655},"antony","Ben Antony",{"slug":1657,"name":1658},"arrasz","Joachim Arrasz",{"slug":1660,"name":1661},"bauer","David Bauer",{"slug":1663,"name":1664},"bechtold","Janine Bechtold",{"slug":1666,"name":1667},"boersig","Jasmin Börsig",{"slug":1669,"name":1670},"buch","Fabian Buch",{"slug":1672,"name":1673},"buchloh","Aljona Buchloh",{"slug":1675,"name":1676},"burgard","Julia Burgard",{"slug":1678,"name":1679},"caspar-schwedes","Caspar Schwedes",{"slug":1681,"name":1682},"christina-schmitt","Christina Schmitt",{"slug":1684,"name":1685},"clausen","Michael Clausen",{"slug":1687,"name":1688},"contargo_poetzsch","Thomas Pötzsch",{"slug":1690,"name":1691},"damrath","Sebastian Damrath",{"slug":1693,"name":1694},"daniel","Markus Daniel",{"slug":1696,"name":1697},"dasch","Julia Dasch",{"slug":1699,"name":1700},"denman","Joffrey Denman",{"slug":1702,"name":1703},"dfuchs","Daniel Fuchs",{"slug":1705,"name":1706},"dobler","Max Dobler",{"slug":1708,"name":1709},"dobriakov","Vladimir Dobriakov",{"slug":1711,"name":1711},"dreiqbik",{"slug":1713,"name":1714},"dschaefer","Denise Schäfer",{"slug":1716,"name":1717},"dschneider","Dominik Schneider",{"slug":1719,"name":1720},"duerlich","Isabell Duerlich",{"slug":1722,"name":1723},"dutkowski","Bernd Dutkowski",{"slug":1725,"name":1725},"eifler",{"slug":1727,"name":1728},"essig","Tim Essig",{"slug":1730,"name":1731},"ferstl","Maximilian Ferstl",{"slug":1733,"name":1734},"fey","Prisca Fey",{"slug":1736,"name":1737},"frank","Leonard Frank",{"slug":1739,"name":1740},"franke","Arnold Franke",{"slug":1742,"name":1743},"frischer","Nicolette Rudmann",{"slug":1745,"name":1746},"fuchs","Petra Fuchs",{"slug":1748,"name":1749},"gari","Sarah Gari",{"slug":1751,"name":1752},"gast","Gast",{"slug":1754,"name":1755},"graf","Johannes Graf",{"slug":1757,"name":1758},"grammlich","Daniela Grammlich",{"slug":1760,"name":1761},"guthardt","Sabrina Guthardt",{"slug":1763,"name":1764},"haeussler","Johannes Häussler",{"slug":1766,"name":1767},"hammann","Daniel Hammann",{"slug":1769,"name":1770},"heetel","Julian Heetel",{"slug":1772,"name":1773},"heft","Florian Heft",{"slug":1775,"name":1776},"heib","Sebastian Heib",{"slug":1778,"name":1779},"heisler","Ida Heisler",{"slug":1781,"name":1782},"helm","Patrick Helm",{"slug":1784,"name":1785},"herbold","Michael Herbold",{"slug":1787,"name":1788},"hofmann","Peter Hofmann",{"slug":1790,"name":1791},"hopf","Florian Hopf",{"slug":1793,"name":1794},"jaud","Alina Jaud",{"slug":1796,"name":1797},"jayasinghe","Robin De Silva Jayasinghe",{"slug":1799,"name":1800},"jbuch","Jonathan Buch",{"slug":1802,"name":1803},"junghanss","Gitta Junghanß",{"slug":1805,"name":1806},"kadyietska","Khrystyna Kadyietska",{"slug":1808,"name":1809},"kannegiesser","Marc Kannegiesser",{"slug":1811,"name":1812},"karoly","Robert Károly",{"slug":1814,"name":1815},"karrasz","Katja Arrasz-Schepanski",{"slug":1817,"name":1818},"kaufmann","Florian Kaufmann",{"slug":1820,"name":1821},"kesler","Mike Kesler",{"slug":1823,"name":1824},"kirchgaessner","Bettina Kirchgäßner",{"slug":1826,"name":1827},"klem","Yannic Klem",{"slug":1829,"name":1830},"klenk","Timo Klenk",{"slug":9,"name":1832},"Tobias Knell",{"slug":1834,"name":1835},"knoll","Anna-Lena Knoll",{"slug":1837,"name":1838},"knorre","Matthias Knorre",{"slug":1840,"name":1841},"koenig","Melanie König",{"slug":1843,"name":1844},"kraft","Thomas Kraft",{"slug":1846,"name":1847},"krupicka","Florian Krupicka",{"slug":1849,"name":1850},"kuehn","Christian Kühn",{"slug":1852,"name":1853},"lange","Christian Lange",{"slug":1855,"name":1856},"larrasz","Luca Arrasz",{"slug":1858,"name":1859},"leist","Sascha Leist",{"slug":1861,"name":1862},"lihs","Michael Lihs",{"slug":1267,"name":1864},"David Linsin",{"slug":1866,"name":1867},"maniyar","Christian Maniyar",{"slug":1869,"name":1870},"martin","Björnie",{"slug":1872,"name":1873},"martin-koch","Martin Koch",{"slug":1875,"name":1876},"matt","Tobias Matt",{"slug":1878,"name":1879},"mennerich","Christian Mennerich",{"slug":1881,"name":1882},"menz","Alexander Menz",{"slug":1884,"name":1885},"meseck","Frederick Meseck",{"slug":1887,"name":1888},"messner","Oliver Messner",{"slug":1890,"name":1891},"michael-ploed","Michael Plöd",{"slug":1893,"name":1894},"mies","Marius Mies",{"slug":1896,"name":1897},"mihai","Alina Mihai",{"slug":1899,"name":1900},"moeller","Jörg Möller",{"slug":1902,"name":1903},"mohr","Rebecca Mohr",{"slug":1905,"name":1906},"moretti","David Moretti",{"slug":1908,"name":1909},"mueller","Sven Müller",{"slug":1911,"name":1912},"muessig","Alexander Müssig",{"slug":1914,"name":1915},"neupokoev","Grigory Neupokoev",{"slug":1917,"name":1918},"nussbaecher","Carmen Nussbächer",{"slug":1920,"name":1921},"ochs","Pascal Ochs",{"slug":1923,"name":1924},"oelhoff","Jan Oelhoff",{"slug":1926,"name":1927},"oengel","Yasin Öngel",{"slug":1929,"name":1930},"oezsoy","Enis Özsoy",{"slug":1932,"name":1933},"posch","Maya Posch",{"slug":1935,"name":1936},"ralfmueller","Ralf Müller",{"slug":1938,"name":1938},"redakteur",{"slug":1940,"name":1941},"reich","Michael Reich",{"slug":1943,"name":1944},"reinhard","Karl-Ludwig Reinhard",{"slug":1946,"name":1947},"rmueller","Rebecca Müller",{"slug":1949,"name":1950},"rosum","Jan Rosum",{"slug":1952,"name":1952},"rueckert",{"slug":1954,"name":1955},"ruessel","Sascha Rüssel",{"slug":1957,"name":1958},"sauter","Moritz Sauter",{"slug":1960,"name":1961},"schaefer","Julian Schäfer",{"slug":1963,"name":1964},"scherer","Petra Scherer",{"slug":1966,"name":1967},"schlicht","Anne Schlicht",{"slug":1969,"name":1970},"schmidt","Jürgen Schmidt",{"slug":1972,"name":1973},"schneider","Tobias Schneider",{"slug":1975,"name":1976},"seber","Benjamin Seber",{"slug":1978,"name":1979},"sommer","Marc Sommer",{"slug":1981,"name":1982},"speaker-fels","Jakob Fels",{"slug":1984,"name":1985},"speaker-gierke","Oliver Gierke",{"slug":1987,"name":1988},"speaker-krupa","Malte Krupa",{"slug":1990,"name":1991},"speaker-mader","Jochen Mader",{"slug":1993,"name":1994},"speaker-meusel","Tim Meusel",{"slug":1996,"name":1997},"speaker-milke","Oliver Milke",{"slug":1999,"name":2000},"speaker-paluch","Mark Paluch",{"slug":2002,"name":2003},"speaker-schad","Jörg Schad",{"slug":2005,"name":2006},"speaker-schalanda","Jochen Schalanda",{"slug":2008,"name":2009},"speaker-schauder","Jens Schauder",{"slug":2011,"name":2012},"speaker-unterstein","Johannes Unterstein",{"slug":2014,"name":2015},"speaker-wolff","Eberhard Wolff",{"slug":2017,"name":2018},"speaker-zoerner","Stefan Zörner",{"slug":2020,"name":2021},"stefan-belger","Stefan Belger",{"slug":2023,"name":2024},"steinegger","Roland Steinegger",{"slug":2026,"name":2027},"stern","sternchen synyx",{"slug":2029,"name":2029},"synyx",{"slug":2031,"name":2032},"szulc","Mateusz Szulc",{"slug":2034,"name":2035},"tamara","Tamara Tunczinger",{"slug":2037,"name":2038},"theuer","Tobias Theuer",{"slug":2040,"name":2041},"thieme","Sandra Thieme",{"slug":2043,"name":2044},"thies-clasen","Marudor",{"slug":2046,"name":2047},"toernstroem","Olle Törnström",{"slug":2049,"name":2050},"ullinger","Max Ullinger",{"slug":2052,"name":2053},"ulrich","Stephan Ulrich",{"slug":2055,"name":2056},"wagner","Stefan Wagner",{"slug":2058,"name":2059},"weigel","Andreas Weigel",{"slug":2061,"name":2062},"werner","Fabian Werner",{"slug":2064,"name":2065},"wolke","Sören Wolke",["Reactive",2067],{"$scookieConsent":2068,"$ssite-config":2070},{"functional":2069,"analytics":2069},false,{"_priority":2071,"env":2075,"name":2076,"url":2077},{"name":2072,"env":2073,"url":2074},-10,-15,0,"production","nuxt-app","https://synyx.de",["Set"],["ShallowReactive",2080],{"category-push-notification":-1,"authors":-1},"/blog/tags/push-notification"]