Chat
If needed, your app users can chat with you to provide you more details about their reported bugs, crashes or feedback. You will be able to fix issues faster and make your customers happier.
Enable
Once your app user is registered with Shake, the chat feature is enabled automatically. Each ticket they send you will be a separate conversation.
This feature is tightly integrated with and follows the lifecycle of your User registration,
which means that calling Shake.unregisterUser
also disconnects the current app user from chat
and they won't receive any new messages until registered again.
Notifications
Shake can notify your app users about new messages sent from the Shake dashboard.
Both remote and local notifications are supported, but are mutually exclusive.
Creating a Push Notifications certificate
Shake supports iOS Remote notifications but your application needs the APS Environment Entitlement enabled.
After enabling this app Capability, Shake needs your certificate to establish a certificate based connection with APNS. Follow the Apple docs and generate a new Push Notifications certificate in the Member Center.
Once the certificate is generated and downloaded to your local machine, double click on the certificate to import it to the KeychainAccess application. If done correctly, the Certificate+PrivateKey combination will be present in your KeychainAccess application under the Certificates tab.
Export the Certificate+PrivateKey combination as a .p12 file and upload the file to Shake Dashboard.
Registering iOS application for remote notifications
To target the specific iOS device, Shake needs the device APNS token.
Call the native registerForRemoteNotifications
method during the application launch, to
always obtain a fresh copy of the device APNS token and forward it to Shake.
- Objective-C
- Swift
@implementation AppDelegate- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions {[UIApplication.sharedApplication registerForRemoteNotifications];/// Rest of the application and Shake setupreturn true;}- (void)application:(UIApplication *)applicationdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {[SHKShake didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];}@end
class AppDelegate: UIResponder, UIApplicationDelegate {override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {UIApplication.shared.registerForRemoteNotifications()/// Rest of the application and Shake setupreturn true}override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {Shake.didRegisterForRemoteNotifications(withDeviceToken: deviceToken)}}
Requesting Notification permissions
To show any kind of notifications to your user, you must request a permission.
Requesting a notifications permission triggers a native alert dialog and can be displayed to a user only once.
Make sure to find a proper place and time to ask for this permission, because if the user doesn't grant permission via the alert dialog, all notifications are disabled and must be enabled manually in the Settings app.
Shake remote notifications require an UNAuthorizationOptions
type alert
, which means that user allows notification banners to
be presented.
- Objective-C
- Swift
[UNUserNotificationCenter.currentNotificationCenter requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {/// Fallback if not granted}];
UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .sound, .alert]) { granted, error in/// Fallback if not granted}
Presenting iOS notifications
To handle foreground notifications, application needs to set itself as the UNUserNotificationCenterDelegate
, and implement
the didReceiveResponse, willPresentNotification methods.
To remain customizable and minimally intrusive to an existing notification logic of your app, Shake requires some additional setup.
Use Shake.report(center: UNUserNotificationCenter ...)
methods to delegate notification presentation logic to Shake.
Shake.isShakeNotification
method can be used to perform an early check for Shake originated notifications and delegate processing so that Shake
internally calls Apple completion handlers.
- Objective-C
- Swift
@import Shake;@import UserNotifications;@interface AppDelegate () <UNUserNotificationCenterDelegate>@end@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {UNUserNotificationCenter.currentNotificationCenter.delegate = self;[SHKShake startWithApiKey:@"app-api-key"];return YES;}- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {if ([SHKShake isShakeNotification:response.notification]){[SHKShake reportNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler];return;}completionHandler();}- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {if ([SHKShake isShakeNotification:notification]){[SHKShake reportNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler];return;}completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound);}@end
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {UNUserNotificationCenter.current().delegate = selfShake.start(apiKey: "app-api-key")return true}override func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {if Shake.isShakeNotification(response.notification) {Shake.report(center, didReceive: response, withCompletionHandler: completionHandler)return;}completionHandler()}override func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {if Shake.isShakeNotification(notification) {Shake.report(center, willPresent: notification, withCompletionHandler: completionHandler)return;}completionHandler([.badge, .sound, .alert])}}
With the setup like above, notifications that originate from Shake are handled by Shake, and all other notifications are handled by your app.
This keeps Shake isolated and configurable, but we do recommend using the above snippets because Shake will internally determine if notification should be presented, and also perform expected actions when notifications are tapped.
Local notifications
If for some reason, you don't want to configure remote notifications for your app, Shake can still schedule them locally.
To enable these, you still need to request the user permission, but there is no need to generate any additional
certificates or register the iOS application for remote notifications with registerForRemoteNotifications
method.
Important thing to note is that local notifications are not shown when app is in the background.
Shake uses isRegisteredForRemoteNotifications
property to determine if the app is configured to receive remote notifications.
If that method returns true
, Shake will disable local notifications and assume that you want to enable remote ones.
Unread messages
If you want to show number of unread chat messages somewhere in your app, you can set the unread messages listener. The listener is called immediately when set and on each change in the number of unread messages for a registered app user:
- Objective-C
- Swift
SHKShake.unreadMessagesListener = ^(NSUInteger count) {// Update count in your text element};
Shake.unreadMessagesListener = { count in// Update number in your text element}
To remove the unread messages listener, use Shake.unreadMessagesListener = nil
.