[APP-786] Native notifications (#1095)

* move `notifee.ts` to notifications folder

* install expo notifications

* add UIBackgroundMode `remote-notifications` to app.json

* fix notifee import in Debug.tsx

* add `google-services.json`

* add `development-device` class to eas.json

* Add `notifications.ts` for native notification handling

* send push token to server

* update `@atproto/api`

* fix putting notif token to server

* fix how push token is uploaded

* fix lint

* enable debug appview proxy header on all platforms

* setup `notifications.ts` to work with app view notifs

* clean up notification handler

* add comments

* update packages to correct versions

* remove notifee

* clean up code a lil

* rename push token endpoint

* remove unnecessary comments

* fix comments

* Remove old background scheduler

* Fixes to push notifications API use

* Bump @atproto/api@0.6.6

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
This commit is contained in:
Ansh 2023-08-23 16:28:51 -07:00 committed by GitHub
parent 32b9648931
commit 8ab5eb6583
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 253 additions and 260 deletions

View file

@ -0,0 +1,101 @@
import * as Notifications from 'expo-notifications'
import {RootStoreModel} from '../../state'
import {resetToTab} from '../../Navigation'
import {devicePlatform, isIOS} from 'platform/detection'
// TODO prod did = did:web:api.bsky.app
export function init(store: RootStoreModel) {
store.onUnreadNotifications(count => Notifications.setBadgeCountAsync(count))
store.onSessionLoaded(async () => {
// request notifications permission once the user has logged in
const perms = await Notifications.getPermissionsAsync()
if (!perms.granted) {
await Notifications.requestPermissionsAsync()
}
// register the push token with the server
const token = await getPushToken()
if (token) {
try {
await store.agent.api.app.bsky.notification.registerPush({
serviceDid: 'did:web:api.staging.bsky.dev',
platform: devicePlatform,
token: token.data,
appId: 'xyz.blueskyweb.app',
})
store.log.debug('Notifications: Sent push token (init)', {
type: token.type,
token: token.data,
})
} catch (error) {
store.log.error('Notifications: Failed to set push token', error)
}
}
// listens for new changes to the push token
// In rare situations, a push token may be changed by the push notification service while the app is running. When a token is rolled, the old one becomes invalid and sending notifications to it will fail. A push token listener will let you handle this situation gracefully by registering the new token with your backend right away.
Notifications.addPushTokenListener(async ({data: t, type}) => {
store.log.debug('Notifications: Push token changed', {t, type})
if (t) {
try {
await store.agent.api.app.bsky.notification.registerPush({
serviceDid: 'did:web:api.staging.bsky.dev',
platform: devicePlatform,
token: t,
appId: 'xyz.blueskyweb.app',
})
store.log.debug('Notifications: Sent push token (event)', {
type,
token: t,
})
} catch (error) {
store.log.error('Notifications: Failed to set push token', error)
}
}
})
})
// handle notifications that are tapped on, regardless of whether the app is in the foreground or background
Notifications.addNotificationReceivedListener(event => {
store.log.debug('Notifications: received', event)
if (event.request.trigger.type === 'push') {
let payload
if (isIOS) {
payload = event.request.trigger.payload
} else {
// TODO: handle android payload deeplink
}
if (payload) {
store.log.debug('Notifications: received payload', payload)
// TODO: deeplink notif here
}
}
})
const sub = Notifications.addNotificationResponseReceivedListener(
response => {
store.log.debug(
'Notifications: response received',
response.actionIdentifier,
)
if (
response.actionIdentifier === Notifications.DEFAULT_ACTION_IDENTIFIER
) {
store.log.debug(
'User pressed a notification, opening notifications tab',
)
resetToTab('NotificationsTab')
}
},
)
return () => {
sub.remove()
}
}
export function getPushToken() {
return Notifications.getDevicePushTokenAsync()
}