diff --git a/android/app/build.gradle b/android/app/build.gradle index c750f2845..d74aec64d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -217,6 +217,10 @@ dependencies { } else { implementation jscFlavor } + + implementation "com.google.code.gson:gson:2.8.5" + implementation "com.github.bumptech.glide:glide:4.9.0" + annotationProcessor "com.github.bumptech.glide:compiler:4.9.0" } // Run this once to be able to run the application with BUCK diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index cba06651e..25f62f1b0 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -47,6 +47,15 @@ + + + > notificationMessages = new HashMap>(); + public static String KEY_REPLY = "KEY_REPLY"; + public static String NOTIFICATION_ID = "NOTIFICATION_ID"; + + public static void clearMessages(int notId) { + notificationMessages.remove(Integer.toString(notId)); + } + + @Override + public void onReceived() throws InvalidNotificationException { + final Bundle bundle = mNotificationProps.asBundle(); + + String notId = bundle.getString("notId"); + String message = bundle.getString("message"); + + if (notificationMessages.get(notId) == null) { + notificationMessages.put(notId, new ArrayList()); + } + notificationMessages.get(notId).add(message); + + super.postNotification(Integer.parseInt(notId)); + + notifyReceivedToJS(); + } + + @Override + public void onOpened() { + Bundle bundle = mNotificationProps.asBundle(); + final String notId = bundle.getString("notId"); + notificationMessages.remove(notId); + digestNotification(); } @Override protected Notification.Builder getNotificationBuilder(PendingIntent intent) { - final Resources res = mContext.getResources(); - String packageName = mContext.getPackageName(); + final Notification.Builder notification = new Notification.Builder(mContext); Bundle bundle = mNotificationProps.asBundle(); - int smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName); - int largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName); String title = bundle.getString("title"); String message = bundle.getString("message"); + String notId = bundle.getString("notId"); - String CHANNEL_ID = "rocketchatrn_channel_01"; - String CHANNEL_NAME = "All"; - - final Notification.Builder notification = new Notification.Builder(mContext) - .setSmallIcon(smallIconResId) + notification .setContentIntent(intent) .setContentTitle(title) .setContentText(message) - .setStyle(new Notification.BigTextStyle().bigText(message)) .setPriority(Notification.PRIORITY_HIGH) .setDefaults(Notification.DEFAULT_ALL) .setAutoCancel(true); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - notification.setColor(mContext.getColor(R.color.notification_text)); - } + Integer notificationId = Integer.parseInt(notId); + notificationChannel(notification); + notificationIcons(notification, bundle); + notificationStyle(notification, notificationId, bundle); + notificationReply(notification, notificationId, bundle); + notificationDismiss(notification, notificationId); + return notification; + } + + private void notifyReceivedToJS() { + mJsIOHelper.sendEventToJS(NOTIFICATION_RECEIVED_EVENT_NAME, mNotificationProps.asBundle(), mAppLifecycleFacade.getRunningReactContext()); + } + + private Bitmap getAvatar(String uri) { + try { + return Glide.with(mContext) + .asBitmap() + .apply(RequestOptions.bitmapTransform(new RoundedCorners(10))) + .load(uri) + .submit(100, 100) + .get(); + } catch (final ExecutionException | InterruptedException e) { + return null; + } + } + + private void notificationIcons(Notification.Builder notification, Bundle bundle) { + final Resources res = mContext.getResources(); + String packageName = mContext.getPackageName(); + + int smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName); + + Gson gson = new Gson(); + Ejson ejson = gson.fromJson(bundle.getString("ejson", "{}"), Ejson.class); + + notification + .setSmallIcon(smallIconResId) + .setLargeIcon(getAvatar(ejson.getAvatarUri())); + } + + private void notificationChannel(Notification.Builder notification) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + String CHANNEL_ID = "rocketchatrn_channel_01"; + String CHANNEL_NAME = "All"; + NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT); @@ -63,10 +146,65 @@ public class CustomPushNotification extends PushNotification { notification.setChannelId(CHANNEL_ID); } - - Bitmap largeIconBitmap = BitmapFactory.decodeResource(res, largeIconResId); - notification.setLargeIcon(largeIconBitmap); - - return notification; } + + private void notificationStyle(Notification.Builder notification, int notId, Bundle bundle) { + Notification.InboxStyle messageStyle = new Notification.InboxStyle(); + List messages = notificationMessages.get(Integer.toString(notId)); + if (messages != null) { + for (int i = 0; i < messages.size(); i++) { + messageStyle.addLine(messages.get(i)); + } + String summary = bundle.getString("summaryText"); + messageStyle.setSummaryText(summary.replace("%n%", Integer.toString(messages.size()))); + notification.setNumber(messages.size()); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + notification.setColor(mContext.getColor(R.color.notification_text)); + } + + notification.setStyle(messageStyle); + } + + private void notificationReply(Notification.Builder notification, int notificationId, Bundle bundle) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + return; + } + String label = "Reply"; + + final Resources res = mContext.getResources(); + String packageName = mContext.getPackageName(); + int smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName); + + Intent replyIntent = new Intent(mContext, ReplyBroadcast.class); + replyIntent.setAction(KEY_REPLY); + replyIntent.putExtra("pushNotification", bundle); + + PendingIntent replyPendingIntent = PendingIntent.getBroadcast(mContext, notificationId, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT); + + RemoteInput remoteInput = new RemoteInput.Builder(KEY_REPLY) + .setLabel(label) + .build(); + + CharSequence title = label; + Notification.Action replyAction = new Notification.Action.Builder(smallIconResId, title, replyPendingIntent) + .addRemoteInput(remoteInput) + .setAllowGeneratedReplies(true) + .build(); + + notification + .setShowWhen(true) + .addAction(replyAction); + } + + private void notificationDismiss(Notification.Builder notification, int notificationId) { + Intent intent = new Intent(mContext, DismissNotification.class); + intent.putExtra(NOTIFICATION_ID, notificationId); + + PendingIntent dismissPendingIntent = PendingIntent.getBroadcast(mContext, notificationId, intent, 0); + + notification.setDeleteIntent(dismissPendingIntent); + } + } diff --git a/android/app/src/main/java/chat/rocket/reactnative/DismissNotification.java b/android/app/src/main/java/chat/rocket/reactnative/DismissNotification.java new file mode 100644 index 000000000..32524a35f --- /dev/null +++ b/android/app/src/main/java/chat/rocket/reactnative/DismissNotification.java @@ -0,0 +1,13 @@ +package chat.rocket.reactnative; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class DismissNotification extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + int notId = intent.getExtras().getInt(CustomPushNotification.NOTIFICATION_ID); + CustomPushNotification.clearMessages(notId); + } +} diff --git a/android/app/src/main/java/chat/rocket/reactnative/Ejson.java b/android/app/src/main/java/chat/rocket/reactnative/Ejson.java new file mode 100644 index 000000000..6ef2dfb3d --- /dev/null +++ b/android/app/src/main/java/chat/rocket/reactnative/Ejson.java @@ -0,0 +1,42 @@ +package chat.rocket.reactnative; + +import android.content.SharedPreferences; + +import chat.rocket.userdefaults.RNUserDefaultsModule; + +public class Ejson { + String host; + String rid; + String type; + Sender sender; + + private String TOKEN_KEY = "reactnativemeteor_usertoken-"; + private SharedPreferences sharedPreferences = RNUserDefaultsModule.getPreferences(CustomPushNotification.reactApplicationContext); + + public String getAvatarUri() { + if (!type.equals("d")) { + return null; + } + return serverURL() + "/avatar/" + this.sender.username + "?rc_token=" + token() + "&rc_uid=" + userId(); + } + + public String token() { + return sharedPreferences.getString(TOKEN_KEY.concat(userId()), ""); + } + + public String userId() { + return sharedPreferences.getString(TOKEN_KEY.concat(serverURL()), ""); + } + + public String serverURL() { + String url = this.host; + if (url.endsWith("/")) { + url = url.substring(0, url.length() - 1); + } + return url; + } + + private class Sender { + String username; + } +} \ No newline at end of file diff --git a/android/app/src/main/java/chat/rocket/reactnative/ReplyBroadcast.java b/android/app/src/main/java/chat/rocket/reactnative/ReplyBroadcast.java new file mode 100644 index 000000000..81c62aeb0 --- /dev/null +++ b/android/app/src/main/java/chat/rocket/reactnative/ReplyBroadcast.java @@ -0,0 +1,157 @@ +package chat.rocket.reactnative; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.RemoteInput; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.os.Build; +import android.os.Bundle; +import android.util.Log; +import java.io.IOException; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.util.HashMap; +import java.util.Map; + +import okhttp3.Call; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +import chat.rocket.userdefaults.RNUserDefaultsModule; +import com.wix.reactnativenotifications.core.NotificationIntentAdapter; + +public class ReplyBroadcast extends BroadcastReceiver { + private Context mContext; + private Bundle bundle; + private NotificationManager notificationManager; + + @Override + public void onReceive(Context context, Intent intent) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + final CharSequence message = getReplyMessage(intent); + if (message == null) { + return; + } + + mContext = context; + bundle = NotificationIntentAdapter.extractPendingNotificationDataFromIntent(intent); + notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + + String notId = bundle.getString("notId"); + + Gson gson = new Gson(); + Ejson ejson = gson.fromJson(bundle.getString("ejson", "{}"), Ejson.class); + + replyToMessage(ejson, Integer.parseInt(notId), message); + } + } + + protected void replyToMessage(final Ejson ejson, final int notId, final CharSequence message) { + String serverURL = ejson.serverURL(); + String rid = ejson.rid; + + if (serverURL == null || rid == null) { + return; + } + + final OkHttpClient client = new OkHttpClient(); + final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); + + String json = buildMessage(rid, message.toString()); + + CustomPushNotification.clearMessages(notId); + + RequestBody body = RequestBody.create(JSON, json); + Request request = new Request.Builder() + .header("x-auth-token", ejson.token()) + .header("x-user-id", ejson.userId()) + .url(String.format("%s/api/v1/chat.sendMessage", serverURL)) + .post(body) + .build(); + + client.newCall(request).enqueue(new okhttp3.Callback() { + @Override + public void onFailure(Call call, IOException e) { + Log.i("RCNotification", String.format("Reply FAILED exception %s", e.getMessage())); + onReplyFailed(notificationManager, notId); + } + + @Override + public void onResponse(Call call, final Response response) throws IOException { + if (response.isSuccessful()) { + Log.d("RCNotification", "Reply SUCCESS"); + onReplySuccess(notificationManager, notId); + } else { + Log.i("RCNotification", String.format("Reply FAILED status %s BODY %s", response.code(), response.body().string())); + onReplyFailed(notificationManager, notId); + } + } + }); + } + + private String getMessageId() { + final String ALPHA_NUMERIC_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + int count = 17; + StringBuilder builder = new StringBuilder(); + while (count-- != 0) { + int character = (int)(Math.random()*ALPHA_NUMERIC_STRING.length()); + builder.append(ALPHA_NUMERIC_STRING.charAt(character)); + } + return builder.toString(); + } + + protected String buildMessage(String rid, String message) { + Gson gsonBuilder = new GsonBuilder().create(); + + Map msgMap = new HashMap(); + msgMap.put("_id", getMessageId()); + msgMap.put("rid", rid); + msgMap.put("msg", message); + msgMap.put("tmid", null); + + Map msg = new HashMap(); + msg.put("message", msgMap); + + String json = gsonBuilder.toJson(msg); + + return json; + } + + protected void onReplyFailed(NotificationManager notificationManager, int notId) { + String CHANNEL_ID = "CHANNEL_ID_REPLY_FAILED"; + + final Resources res = mContext.getResources(); + String packageName = mContext.getPackageName(); + int smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName); + + NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_ID, NotificationManager.IMPORTANCE_LOW); + notificationManager.createNotificationChannel(channel); + Notification notification = + new Notification.Builder(mContext, CHANNEL_ID) + .setContentTitle("Failed to reply message.") + .setSmallIcon(smallIconResId) + .build(); + + notificationManager.notify(notId, notification); + } + + protected void onReplySuccess(NotificationManager notificationManager, int notId) { + notificationManager.cancel(notId); + } + + private CharSequence getReplyMessage(Intent intent) { + Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); + if (remoteInput != null) { + return remoteInput.getCharSequence(CustomPushNotification.KEY_REPLY); + } + return null; + } +} diff --git a/app/notifications/push/push.ios.js b/app/notifications/push/push.ios.js index 752eae69c..5207e843d 100644 --- a/app/notifications/push/push.ios.js +++ b/app/notifications/push/push.ios.js @@ -1,6 +1,17 @@ -import NotificationsIOS from 'react-native-notifications'; +import NotificationsIOS, { NotificationAction, NotificationCategory } from 'react-native-notifications'; import reduxStore from '../../lib/createStore'; +import I18n from '../../i18n'; + +const replyAction = new NotificationAction({ + activationMode: 'background', + title: I18n.t('Reply'), + textInput: { + buttonTitle: I18n.t('Reply'), + placeholder: I18n.t('Type_message') + }, + identifier: 'REPLY_ACTION' +}); class PushNotification { constructor() { @@ -20,7 +31,12 @@ class PushNotification { completion(); }); - NotificationsIOS.requestPermissions(); + const actions = []; + actions.push(new NotificationCategory({ + identifier: 'MESSAGE', + actions: [replyAction] + })); + NotificationsIOS.requestPermissions(actions); } getDeviceToken() { diff --git a/app/sagas/login.js b/app/sagas/login.js index 3e0415914..ac2a9b9a1 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -111,6 +111,7 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) { }); yield RNUserDefaults.set(`${ RocketChat.TOKEN_KEY }-${ server }`, user.id); + yield RNUserDefaults.set(`${ RocketChat.TOKEN_KEY }-${ user.id }`, user.token); yield put(setUser(user)); EventEmitter.emit('connected'); diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 584c8bd2f..aa95c9b9c 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -381,7 +381,7 @@ PODS: - React - RNScreens (2.0.0-alpha.3): - React - - RNUserDefaults (1.3.5): + - RNUserDefaults (1.7.0): - React - RNVectorIcons (6.6.0): - React @@ -756,7 +756,7 @@ SPEC CHECKSUMS: RNReanimated: b2ab0b693dddd2339bd2f300e770f6302d2e960c RNRootView: 895a4813dedeaca82db2fa868ca1c333d790e494 RNScreens: 402a99b0a27c0c32f079cec12d3ccbd35e20cd7f - RNUserDefaults: 8a4928443510aa99e4ccb3b53f1bf186593d690b + RNUserDefaults: af71a1cdf1c12baf8210bc741c65f5faba9826d6 RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4 RSKImageCropper: a446db0e8444a036b34f3c43db01b2373baa4b2a SDWebImage: 96d7f03415ccb28d299d765f93557ff8a617abd8 diff --git a/ios/Pods/Local Podspecs/RNUserDefaults.podspec.json b/ios/Pods/Local Podspecs/RNUserDefaults.podspec.json index fad4039be..07aed251b 100644 --- a/ios/Pods/Local Podspecs/RNUserDefaults.podspec.json +++ b/ios/Pods/Local Podspecs/RNUserDefaults.podspec.json @@ -1,13 +1,13 @@ { "name": "RNUserDefaults", - "version": "1.3.5", - "summary": "Use `UserDefaults` (iOS) with React Native and `AsyncStorage` on AndroidOS.", - "description": "Use `UserDefaults` (iOS) with React Native and `AsyncStorage` on AndroidOS.", + "version": "1.7.0", + "summary": "Use `UserDefaults` (iOS) with React Native and `SharedPreferences` on AndroidOS.", + "description": "Use `UserDefaults` (iOS) with React Native and `SharedPreferences` on AndroidOS.", "license": "MIT", "authors": "djorkaeffalexandre", - "homepage": "https://github.com/djorkaeffalexandre/rn-user-defaults", + "homepage": "https://github.com/RocketChat/rn-user-defaults.git", "source": { - "git": "https://github.com/djorkaeffalexandre/rn-user-defaults.git" + "git": "https://github.com/RocketChat/rn-user-defaults.git" }, "requires_arc": true, "platforms": { diff --git a/ios/Pods/Manifest.lock b/ios/Pods/Manifest.lock index 584c8bd2f..aa95c9b9c 100644 --- a/ios/Pods/Manifest.lock +++ b/ios/Pods/Manifest.lock @@ -381,7 +381,7 @@ PODS: - React - RNScreens (2.0.0-alpha.3): - React - - RNUserDefaults (1.3.5): + - RNUserDefaults (1.7.0): - React - RNVectorIcons (6.6.0): - React @@ -756,7 +756,7 @@ SPEC CHECKSUMS: RNReanimated: b2ab0b693dddd2339bd2f300e770f6302d2e960c RNRootView: 895a4813dedeaca82db2fa868ca1c333d790e494 RNScreens: 402a99b0a27c0c32f079cec12d3ccbd35e20cd7f - RNUserDefaults: 8a4928443510aa99e4ccb3b53f1bf186593d690b + RNUserDefaults: af71a1cdf1c12baf8210bc741c65f5faba9826d6 RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4 RSKImageCropper: a446db0e8444a036b34f3c43db01b2373baa4b2a SDWebImage: 96d7f03415ccb28d299d765f93557ff8a617abd8 diff --git a/ios/RocketChatRN/Info.plist b/ios/RocketChatRN/Info.plist index 7b31b54b7..9365ee0e8 100644 --- a/ios/RocketChatRN/Info.plist +++ b/ios/RocketChatRN/Info.plist @@ -85,6 +85,7 @@ UIBackgroundModes + fetch voip UILaunchStoryboardName diff --git a/package.json b/package.json index 7174582f8..7ebab36e6 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "rn-extensions-share": "^2.3.10", "rn-fetch-blob": "0.11.2", "rn-root-view": "^1.0.3", - "rn-user-defaults": "^1.3.5", + "rn-user-defaults": "^1.7.0", "semver": "6.3.0", "snyk": "1.210.0", "strip-ansi": "5.2.0", diff --git a/patches/react-native-notifications+2.0.6.patch b/patches/react-native-notifications+2.0.6.patch new file mode 100644 index 000000000..b531954b4 --- /dev/null +++ b/patches/react-native-notifications+2.0.6.patch @@ -0,0 +1,99 @@ +diff --git a/node_modules/react-native-notifications/RNNotifications/RNNotificationEventHandler.m b/node_modules/react-native-notifications/RNNotifications/RNNotificationEventHandler.m +index edc4fd4..aeb5eaa 100644 +--- a/node_modules/react-native-notifications/RNNotifications/RNNotificationEventHandler.m ++++ b/node_modules/react-native-notifications/RNNotifications/RNNotificationEventHandler.m +@@ -28,9 +28,92 @@ - (void)didReceiveForegroundNotification:(UNNotification *)notification withComp + [RNEventEmitter sendEvent:RNNotificationReceivedForeground body:[RNNotificationParser parseNotification:notification]]; + } + ++/* ++ * Generate a random alphanumeric string to message id ++*/ ++-(NSString *)random:(int)len { ++ NSString *letters = @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; ++ NSMutableString *randomString = [NSMutableString stringWithCapacity:len]; ++ ++ for (int i=0; i 0) { ++ unichar last = [host characterAtIndex:[host length] - 1]; ++ if (last == '/') { ++ host = [host substringToIndex:[host length] - 1]; ++ } ++ } ++ return host; ++} ++ + - (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(void))completionHandler { +- [_store setActionCompletionHandler:completionHandler withCompletionKey:response.notification.request.identifier]; +- [RNEventEmitter sendEvent:RNNotificationOpened body:[RNNotificationParser parseNotificationResponse:response]]; ++ // if notification response is a REPLY_ACTION ++ if ([response.actionIdentifier isEqualToString:@"REPLY_ACTION"]) { ++ // convert notification data to dictionary payload ++ NSDictionary *notification = [RCTConvert UNNotificationPayload:response.notification]; ++ ++ // parse ejson from notification ++ NSData *ejsonData = [[notification valueForKey:@"ejson"] dataUsingEncoding:NSUTF8StringEncoding]; ++ NSError *error; ++ NSDictionary *ejson = [NSJSONSerialization JSONObjectWithData:ejsonData options:kNilOptions error:&error]; ++ ++ // data from notification ++ NSString *host = [ejson valueForKey:@"host"]; ++ NSString *rid = [ejson valueForKey:@"rid"]; ++ ++ // msg on textinput of notification ++ NSString *msg = [(UNTextInputNotificationResponse *)response userText]; ++ ++ // get credentials ++ NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.ios.chat.rocket"]; ++ NSString *TOKEN_KEY = @"reactnativemeteor_usertoken"; ++ NSString *userId = [userDefaults stringForKey:[NSString stringWithFormat:@"%@-%@", TOKEN_KEY, [self serverURL:host]]]; ++ NSString *token = [userDefaults stringForKey:[NSString stringWithFormat:@"%@-%@", TOKEN_KEY, userId]]; ++ ++ // background task - we need this because fetch doesn't work if app is closed/killed ++ UIApplication *app = [UIApplication sharedApplication]; ++ __block UIBackgroundTaskIdentifier task = [app beginBackgroundTaskWithExpirationHandler:^{ ++ [app endBackgroundTask:task]; ++ task = UIBackgroundTaskInvalid; ++ }]; ++ // we use global queue to make requests with app closed/killed ++ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ ++ // we make a synchronous request to post new message ++ NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/api/v1/chat.sendMessage", [self serverURL:host]]]]; ++ ++ NSString *message = [NSString stringWithFormat:@"{ \"message\": { \"_id\": \"%@\", \"msg\": \"%@\", \"rid\": \"%@\" } }", [self random:17], msg, rid]; ++ ++ [request setHTTPMethod:@"POST"]; ++ [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; ++ [request addValue:userId forHTTPHeaderField:@"x-user-id"]; ++ [request addValue:token forHTTPHeaderField:@"x-auth-token"]; ++ [request setHTTPBody:[message dataUsingEncoding:NSUTF8StringEncoding]]; ++ ++ NSURLResponse *response = nil; ++ NSError *error = nil; ++ NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; ++ ++ // end background task ++ [app endBackgroundTask:task]; ++ task = UIBackgroundTaskInvalid; ++ ++ // complete notification response ++ completionHandler(); ++ }); ++ } else { ++ // We only set initial notification and emit event to JS when not is a reply action ++ [_store setActionCompletionHandler:completionHandler withCompletionKey:response.notification.request.identifier]; ++ [RNEventEmitter sendEvent:RNNotificationOpened body:[RNNotificationParser parseNotificationResponse:response]]; ++ } + } + + @end \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index d951ff215..20d400964 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10219,10 +10219,10 @@ rn-root-view@^1.0.3: resolved "https://registry.yarnpkg.com/rn-root-view/-/rn-root-view-1.0.3.tgz#a2cddc717278cb2175fb29b7c006e407b7f0d0e2" integrity sha512-BIKm8hY5q8+pxK9B5ugYjqutoI9xn2JfxIZKWoaFmAl1bOIM4oXjwFQrRM1e6lFgzz99MN6Mf2dK3Alsywnvvw== -rn-user-defaults@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/rn-user-defaults/-/rn-user-defaults-1.3.5.tgz#8a93325e3fbbc47b1abd4147dc39b25eec8a45ab" - integrity sha512-mqB57aQBb88QK49revJeJGMQXkPl2qtLeF4mINa7XTVCruAruNkm5wgTKLyS5aNLWdd3XIjkkAUSgH6o6FvIVQ== +rn-user-defaults@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/rn-user-defaults/-/rn-user-defaults-1.7.0.tgz#8d1b79657dec3977e8f8983814b8591821f77236" + integrity sha512-Qo6sIH8wldmQ0oOMMvljec4WOa/a1Up1pdatoXZGaPG1gl8OKgKH5HPKyddcABYtxPeBUTPVzCxP/6S6wPCqGQ== rsvp@^3.3.3: version "3.6.2"