Skip to content
Snippets Groups Projects
Commit c86a3d63 authored by Sébastiaan Versteeg's avatar Sébastiaan Versteeg
Browse files

Add push notification functionality

parent c22cc3d8
No related branches found
No related tags found
1 merge request!26Push Notifications
Showing
with 481 additions and 39 deletions
......@@ -22,6 +22,10 @@ DerivedData
*.xcuserstate
project.xcworkspace
# Pods
#
ios/Pods
# Android/IntelliJ
#
build/
......
......@@ -141,11 +141,13 @@ android {
}
dependencies {
compile project(':react-native-fcm')
compile project(':react-native-linear-gradient')
compile project(':react-native-vector-icons')
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:+" // From node_modules
compile 'com.google.firebase:firebase-core:11.4.0'
}
// Run this once to be able to run the application with BUCK
......@@ -162,3 +164,5 @@ gradle.projectsEvaluated {
processBuilder.start()
}
}
apply plugin: 'com.google.gms.google-services'
\ No newline at end of file
{
"project_info": {
"project_number": "488731759938",
"firebase_url": "https://thalia-493a0.firebaseio.com",
"project_id": "thalia-493a0",
"storage_bucket": "thalia-493a0.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:488731759938:android:ce90d9e7effcbbfb",
"android_client_info": {
"package_name": "com.thaliapp"
}
},
"oauth_client": [
{
"client_id": "488731759938-k103fp2m146qhfsf7s3to9bm43qhcous.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyApn30VsmPqjs4N5_kR68tpXzBWSyOxuoM"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:488731759938:android:e73d72886d6d4f94",
"android_client_info": {
"package_name": "com.thaliapp.dev"
}
},
"oauth_client": [
{
"client_id": "488731759938-k103fp2m146qhfsf7s3to9bm43qhcous.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyApn30VsmPqjs4N5_kR68tpXzBWSyOxuoM"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
}
}
}
],
"configuration_version": "1"
}
\ No newline at end of file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.thaliapp"
android:versionCode="1"
android:versionName="1.0">
package="com.thaliapp"
android:versionCode="1"
android:versionName="1.0">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="22" />
android:minSdkVersion="16"
android:targetSdkVersion="22"/>
<application
android:name=".MainApplication"
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
android:name=".MainApplication"
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
<meta-data android:name="android.max_aspect" android:value="2.1" />
<service android:name="com.evollu.react.fcm.MessagingService" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service android:name="com.evollu.react.fcm.InstanceIdService" android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@mipmap/ic_notification" />
<meta-data
android:name="android.max_aspect"
android:value="2.1" />
</application>
</manifest>
......@@ -3,6 +3,7 @@ package com.thaliapp;
import android.app.Application;
import com.facebook.react.ReactApplication;
import com.evollu.react.fcm.FIRMessagingPackage;
import com.BV.LinearGradient.LinearGradientPackage;
import com.oblador.vectoricons.VectorIconsPackage;
import com.facebook.react.ReactNativeHost;
......@@ -25,6 +26,7 @@ public class MainApplication extends Application implements ReactApplication {
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new FIRMessagingPackage(),
new LinearGradientPackage(),
new VectorIconsPackage()
);
......
android/app/src/main/res/mipmap-hdpi/ic_notification.png

730 B

android/app/src/main/res/mipmap-mdpi/ic_notification.png

425 B

android/app/src/main/res/mipmap-xhdpi/ic_notification.png

791 B

android/app/src/main/res/mipmap-xxhdpi/ic_notification.png

1.33 KiB

android/app/src/main/res/mipmap-xxxhdpi/ic_notification.png

1.73 KiB

......@@ -6,6 +6,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
classpath 'com.google.gms:google-services:3.1.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
......@@ -20,5 +21,8 @@ allprojects {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
maven {
url "https://maven.google.com" // Google's Maven repository
}
}
}
rootProject.name = 'ThaliApp'
include ':react-native-fcm'
project(':react-native-fcm').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fcm/android')
include ':react-native-linear-gradient'
project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android')
include ':react-native-vector-icons'
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
include ':app'
include ':app'
\ No newline at end of file
export const REGISTER = 'PUSH_NOTIFICATIONS_REGISTER';
export const INVALIDATE = 'PUSH_NOTIFICATIONS_INVALIDATE';
export function register(token) {
return { type: REGISTER, payload: { token } };
}
export function invalidate() {
return { type: INVALIDATE };
}
......@@ -4,6 +4,7 @@ import { applyMiddleware, combineReducers, createStore } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import createSagaMiddleware from 'redux-saga';
import FCM, { FCMEvent } from 'react-native-fcm';
import Moment from 'moment';
import 'moment/locale/nl';
......@@ -11,6 +12,7 @@ import * as reducers from './reducers';
import sagas from './sagas';
import ReduxNavigator from './components/navigator';
import * as loginActions from './actions/login';
import { register } from './actions/pushNotifications';
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const sagaMiddleware = createSagaMiddleware();
......@@ -29,6 +31,20 @@ const pairsToObject = (obj, pair) => {
return obj2;
};
FCM.on(FCMEvent.Notification, async (notif) => {
if (notif.fcm) {
FCM.presentLocalNotification({
title: notif.fcm.title,
body: notif.fcm.body,
color: notif.fcm.color,
icon: notif.fcm.icon === null ? 'ic_notification' : notif.fcm.icon,
action: notif.fcm.action,
tag: notif.fcm.tag,
show_in_foreground: true,
});
}
});
class Main extends Component {
componentDidMount() {
Moment.locale('nl');
......@@ -43,6 +59,7 @@ class Main extends Component {
if (username !== null && token !== null) {
store.dispatch(loginActions.success(username, token, displayName, photo, ''));
store.dispatch(register(token));
}
});
}
......
......@@ -5,6 +5,7 @@ import eventSaga from './event';
import profileSaga from './profile';
import welcomeSaga from './welcome';
import calendarSaga from './calendar';
import pushNotificationsSaga from './pushNotifications';
const sagas = function* sagas() {
yield all([
......@@ -13,6 +14,7 @@ const sagas = function* sagas() {
fork(profileSaga),
fork(welcomeSaga),
fork(calendarSaga),
fork(pushNotificationsSaga),
]);
};
......
......@@ -4,6 +4,7 @@ import { AsyncStorage } from 'react-native';
import { apiRequest, url } from '../url';
import * as loginActions from '../actions/login';
import * as pushNotificationsActions from '../actions/pushNotifications';
const USERNAMEKEY = '@MyStore:username';
const TOKENKEY = '@MyStore:token';
......@@ -52,6 +53,7 @@ const login = function* login(action) {
yield put(loginActions.success(
user, token, displayName, avatar,
));
yield put(pushNotificationsActions.register(token));
yield delay(2000);
yield put(loginActions.reset());
} catch (error) {
......@@ -64,6 +66,7 @@ const login = function* login(action) {
const logout = function* logout() {
yield call(AsyncStorage.multiRemove, [USERNAMEKEY, TOKENKEY]);
yield delay(2000);
yield put(pushNotificationsActions.invalidate());
yield put(loginActions.reset());
};
......
import { call, takeEvery } from 'redux-saga/effects';
import { Platform } from 'react-native';
import FCM from 'react-native-fcm';
import { apiRequest } from '../url';
import * as pushNotificationsActions from '../actions/pushNotifications';
const register = function* register(action) {
const { token } = action.payload;
let pushToken;
if (Platform.OS === 'ios') {
pushToken = yield call(FCM.getFCMToken);
} else {
yield call(FCM.requestPermissions);
pushToken = yield call(FCM.getFCMToken);
}
const data = {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Token ${token}`,
},
body: JSON.stringify({
registration_id: pushToken,
type: Platform.OS,
}),
};
yield call(apiRequest, 'devices', data);
};
const invalidate = function* invalidate() {
yield call(FCM.deleteInstanceId);
};
const pushNotificationsSaga = function* pushNotificationsSaga() {
yield takeEvery(pushNotificationsActions.REGISTER, register);
yield takeEvery(pushNotificationsActions.INVALIDATE, invalidate);
};
export default pushNotificationsSaga;
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'ThaliApp' do
# Uncomment the next line if you're using Swift or would like to use dynamic frameworks
# use_frameworks!
# Pods for ThaliApp
pod 'FirebaseMessaging'
target 'ThaliAppTests' do
inherit! :search_paths
# Pods for testing
end
end
PODS:
- FirebaseAnalytics (3.6.0):
- FirebaseCore (~> 3.4)
- FirebaseInstanceID (~> 1.0)
- GoogleInterchangeUtilities (~> 1.2)
- GoogleSymbolUtilities (~> 1.1)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- FirebaseCore (3.4.6):
- GoogleInterchangeUtilities (~> 1.2)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- FirebaseInstanceID (1.0.8)
- FirebaseMessaging (1.2.1):
- FirebaseAnalytics (~> 3.4)
- FirebaseInstanceID (~> 1.0)
- GoogleInterchangeUtilities (~> 1.2)
- GoogleSymbolUtilities (~> 1.1)
- GoogleToolboxForMac/Logger (~> 2.1)
- GoogleInterchangeUtilities (1.2.2):
- GoogleSymbolUtilities (~> 1.1)
- GoogleSymbolUtilities (1.1.2)
- GoogleToolboxForMac/Defines (2.1.0)
- GoogleToolboxForMac/Logger (2.1.0):
- GoogleToolboxForMac/Defines (= 2.1.0)
- GoogleToolboxForMac/NSData+zlib (2.1.0):
- GoogleToolboxForMac/Defines (= 2.1.0)
DEPENDENCIES:
- FirebaseMessaging
SPEC CHECKSUMS:
FirebaseAnalytics: 9c67af0ebeb8d2146c9b4ea2616439affa947b58
FirebaseCore: 03da1cb32615569bbc2830a22f9ad753d9a02ef5
FirebaseInstanceID: ba1e640935235e5fac39dfa816fe7660e72e1a8a
FirebaseMessaging: acf66347e43c5637c697060c3001d25c809a4131
GoogleInterchangeUtilities: d5bc4d88d5b661ab72f9d70c58d02ca8c27ad1f7
GoogleSymbolUtilities: 631ee17048aa5e9ab133470d768ea997a5ef9b96
GoogleToolboxForMac: 2b2596cbb7186865e98cadf2b1e262d851c2b168
PODFILE CHECKSUM: e96d08e64ae034c5cc5d47d35f4df47f936e7fc3
COCOAPODS: 1.2.1
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment