Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of ios push notifications #746

Merged
merged 2 commits into from
Jul 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
"jsonp", "otp", "Otp", "ascii", "Ascii", "substr", "Util", "actionsheet", "unmute",
"otp", "Otp", "ascii", "Ascii", "substr", "Util", "actionsheet", "jsonp", "actionsheet", "ionicons",
"denmark", "copenhagen", "unregister", "gcm", "unstarMessage", "Unstar", "wildcard_mentioned",
"lightbox", "resize", "remobile", "multiline", "uniqby", "zoe", "localizable",
"lightbox", "resize", "remobile", "multiline", "uniqby", "zoe", "localizable", "appid", "apns"
],
"skipIfMatch": [
"http://[^s]*",
Expand Down
57 changes: 53 additions & 4 deletions ios/ZulipMobile.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
17449DB932594E96A837970F /* MaterialIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 51E1EDA028654E17A35C5BCA /* MaterialIcons.ttf */; };
3556F3DAC2424EBE9ABF0A31 /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 2E41C86FA25744F998C2BB02 /* Zocial.ttf */; };
3C4249EB1EF6E09F00D245F1 /* libRNNotifications.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C4249E61EF6E05C00D245F1 /* libRNNotifications.a */; };
48D1FC73615948D79D3BD31E /* Octicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = A7F287C57D8A4354A8B6A3E7 /* Octicons.ttf */; };
49692FC0562C40F3946EC6D4 /* Foundation.ttf in Resources */ = {isa = PBXBuildFile; fileRef = A752523B8D8E49E792F653E1 /* Foundation.ttf */; };
4B12DC82ECA043809695F227 /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9DB2E7AE39A448A98E7A4E4A /* Ionicons.ttf */; };
Expand Down Expand Up @@ -118,6 +119,13 @@
remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
remoteInfo = React;
};
3C4249E51EF6E05C00D245F1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 3C4249C61EF6E05C00D245F1 /* RNNotifications.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RNNotifications;
};
78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
Expand Down Expand Up @@ -319,6 +327,8 @@
2CFB39BBD9094475BB03A3E4 /* libRCTToast.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTToast.a; sourceTree = "<group>"; };
2E41C86FA25744F998C2BB02 /* Zocial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Zocial.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Zocial.ttf"; sourceTree = "<group>"; };
3074EDA2D113487A925E187C /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = "<group>"; };
3C4249C61EF6E05C00D245F1 /* RNNotifications.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNNotifications.xcodeproj; path = "../node_modules/react-native-notifications/RNNotifications/RNNotifications.xcodeproj"; sourceTree = "<group>"; };
3C4249EC1EF6E16500D245F1 /* ZulipMobile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = ZulipMobile.entitlements; path = ZulipMobile/ZulipMobile.entitlements; sourceTree = "<group>"; };
51E1EDA028654E17A35C5BCA /* MaterialIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf"; sourceTree = "<group>"; };
6922647B10C64653A76BF3E5 /* RCTToast.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTToast.xcodeproj; path = "../node_modules/@remobile/react-native-toast/ios/RCTToast.xcodeproj"; sourceTree = "<group>"; };
6DA76D9085EA458BB979ED8D /* RNVectorIcons.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNVectorIcons.xcodeproj; path = "../node_modules/react-native-vector-icons/RNVectorIcons.xcodeproj"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -382,6 +392,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
3C4249EB1EF6E09F00D245F1 /* libRNNotifications.a in Frameworks */,
CFCFE5491F00158500C295CF /* libRCTCameraRoll.a in Frameworks */,
A14EA8771EACE522009D9E83 /* libRCTAnimation.a in Frameworks */,
146834051AC3E58100842450 /* libReact.a in Frameworks */,
Expand Down Expand Up @@ -488,6 +499,7 @@
13B07FAE1A68108700A75B9A /* ZulipMobile */ = {
isa = PBXGroup;
children = (
3C4249EC1EF6E16500D245F1 /* ZulipMobile.entitlements */,
008F07F21AC5B25A0029DE68 /* main.jsbundle */,
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.m */,
Expand Down Expand Up @@ -535,6 +547,14 @@
name = Frameworks;
sourceTree = "<group>";
};
3C4249C71EF6E05C00D245F1 /* Products */ = {
isa = PBXGroup;
children = (
3C4249E61EF6E05C00D245F1 /* libRNNotifications.a */,
);
name = Products;
sourceTree = "<group>";
};
58A37319FEF489FE2CFCFA3F /* Pods */ = {
isa = PBXGroup;
children = (
Expand All @@ -558,6 +578,7 @@
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup;
children = (
3C4249C61EF6E05C00D245F1 /* RNNotifications.xcodeproj */,
A14EA8541EACE4CE009D9E83 /* RCTAnimation.xcodeproj */,
A155BFE71DD8E54100A8B695 /* RCTCameraRoll.xcodeproj */,
146833FF1AC3E56700842450 /* React.xcodeproj */,
Expand Down Expand Up @@ -766,7 +787,16 @@
TestTargetID = 13B07F861A680F5B00A75B9A;
};
13B07F861A680F5B00A75B9A = {
DevelopmentTeam = 66KHCWMEYB;
DevelopmentTeam = 6GJ3LH2XZ2;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.BackgroundModes = {
enabled = 0;
};
com.apple.Push = {
enabled = 1;
};
};
};
};
};
Expand Down Expand Up @@ -842,6 +872,10 @@
ProductGroup = CFCFE50D1F0011FA00C295CF /* Products */;
ProjectRef = FC7EC6A752C243FB9F1B8442 /* RNFetchBlob.xcodeproj */;
},
{
ProductGroup = 3C4249C71EF6E05C00D245F1 /* Products */;
ProjectRef = 3C4249C61EF6E05C00D245F1 /* RNNotifications.xcodeproj */;
},
{
ProductGroup = A148FEDC1E9D8C9600479280 /* Products */;
ProjectRef = AF03F5DAC0924A13BDD49574 /* RNSound.xcodeproj */;
Expand Down Expand Up @@ -924,6 +958,13 @@
remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
3C4249E61EF6E05C00D245F1 /* libRNNotifications.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRNNotifications.a;
remoteRef = 3C4249E51EF6E05C00D245F1 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
Expand Down Expand Up @@ -1390,7 +1431,10 @@
baseConfigurationReference = 2BBAAB1FE905B6D60DE187DD /* Pods-ZulipMobile.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = ZulipMobile/ZulipMobile.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = 6GJ3LH2XZ2;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
HEADER_SEARCH_PATHS = (
"$(inherited)",
Expand All @@ -1403,6 +1447,7 @@
"$(SRCROOT)/../node_modules/react-native-safari-view",
"$(SRCROOT)/../node_modules/@remobile/react-native-toast/ios/RCTToast",
"$(SRCROOT)/../node_modules/react-native-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-notifications/**",
);
INFOPLIST_FILE = ZulipMobile/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
Expand All @@ -1412,8 +1457,9 @@
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = org.zulip.Zulip;
PRODUCT_BUNDLE_IDENTIFIER = com.zulip.Zulip;
PRODUCT_NAME = ZulipMobile;
PROVISIONING_PROFILE_SPECIFIER = "";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
Expand All @@ -1423,7 +1469,8 @@
baseConfigurationReference = 8FC8D6AFD281F51DCA6E1C99 /* Pods-ZulipMobile.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = D47VARCYH7;
CODE_SIGN_ENTITLEMENTS = ZulipMobile/ZulipMobile.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
HEADER_SEARCH_PATHS = (
"$(inherited)",
Expand All @@ -1436,6 +1483,7 @@
"$(SRCROOT)/../node_modules/react-native-safari-view",
"$(SRCROOT)/../node_modules/@remobile/react-native-toast/ios/RCTToast",
"$(SRCROOT)/../node_modules/react-native-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-notifications/**",
);
INFOPLIST_FILE = ZulipMobile/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
Expand All @@ -1445,8 +1493,9 @@
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = org.zulip.Zulip;
PRODUCT_BUNDLE_IDENTIFIER = com.zulip.Zulip;
PRODUCT_NAME = ZulipMobile;
PROVISIONING_PROFILE_SPECIFIER = "";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
Expand Down
25 changes: 25 additions & 0 deletions ios/ZulipMobile/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#import <Crashlytics/Crashlytics.h>
#import <asl.h>
#import "RCTLog.h"
#import "RNNotifications.h"

@implementation AppDelegate

Expand Down Expand Up @@ -99,5 +100,29 @@ - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserAct
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
// Required to register for notifications
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
[RNNotifications didRegisterUserNotificationSettings:notificationSettings];
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[RNNotifications didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
[RNNotifications didFailToRegisterForRemoteNotificationsWithError:error];
}

// Required for the notification event.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification {
[RNNotifications didReceiveRemoteNotification:notification];
}

// Required for the localNotification event.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
[RNNotifications didReceiveLocalNotification:notification];
}
@end
8 changes: 8 additions & 0 deletions ios/ZulipMobile/ZulipMobile.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
</dict>
</plist>
20 changes: 10 additions & 10 deletions src/account-info/LogoutButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { InitRouteAction, Auth } from '../types';
import boundActions from '../boundActions';
import { getInitialRoutes } from '../nav/routingSelectors';
import { ZulipButton } from '../common';
import unregisterGCM from '../api/unregisterGCM';
import unregisterPush from '../api/unregisterPush';
import { getAuth } from '../account/accountSelectors';

const styles = StyleSheet.create({
Expand All @@ -23,22 +23,22 @@ class LogoutButton extends Component {
accounts: any[],
initRoutes: InitRouteAction,
logout: (accounts: any[]) => void,
deleteTokenGCM: () => void,
deleteTokenPush: () => void,
auth: Auth,
gcmToken: string,
pushToken: string,
};

shutdownGCM = async () => {
const { auth, deleteTokenGCM, gcmToken } = this.props;
if (gcmToken !== '') {
await unregisterGCM(auth, gcmToken);
deleteTokenGCM();
shutdownPUSH = async () => {
const { auth, deleteTokenPush, pushToken } = this.props;
if (pushToken !== '') {
await unregisterPush(auth, pushToken);
deleteTokenPush();
}
}

logout = () => {
const { accounts } = this.props;
this.shutdownGCM();
this.shutdownPUSH();
this.props.logout(accounts);
const accountsLoggedOut = accounts.slice();
accountsLoggedOut[0].apiKey = '';
Expand All @@ -61,7 +61,7 @@ export default connect(
(state) => ({
auth: getAuth(state),
accounts: state.accounts,
gcmToken: state.realm.gcmToken
pushToken: state.realm.pushToken
}),
boundActions,
)(LogoutButton);
16 changes: 8 additions & 8 deletions src/account-info/SwitchAccountButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { connect } from 'react-redux';
import boundActions from '../boundActions';
import { ZulipButton } from '../common';
import { getAuth } from '../account/accountSelectors';
import unregisterGCM from '../api/unregisterGCM';
import unregisterPush from '../api/unregisterPush';

const styles = StyleSheet.create({
button: {
Expand All @@ -21,16 +21,16 @@ class SwitchAccountButton extends Component {
drawer: () => null,
};

shutdownGCM = async () => {
const { auth, deleteTokenGCM, gcmToken } = this.props;
if (gcmToken !== '') {
await unregisterGCM(auth, gcmToken);
deleteTokenGCM();
shutdownPUSH = async () => {
const { auth, deleteTokenPush, pushToken } = this.props;
if (pushToken !== '') {
await unregisterPush(auth, pushToken);
deleteTokenPush();
}
}

switchAccount = () => {
this.shutdownGCM();
this.shutdownPUSH();
this.context.drawer.close();
this.props.pushRoute('account');
}
Expand All @@ -51,7 +51,7 @@ export default connect(
(state) => ({
auth: getAuth(state),
accounts: state.accounts,
gcmToken: state.realm.gcmToken
pushToken: state.realm.pushToken
}),
boundActions,
)(SwitchAccountButton);
4 changes: 2 additions & 2 deletions src/actionConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ export const GET_USER_RESPONSE = 'GET_USER_RESPONSE';
export const MARK_MESSAGES_READ = 'MARK_MESSAGES_READ';
export const SETTINGS_CHANGE = 'SETTINGS_CHANGE';

export const SAVE_TOKEN_GCM = 'SAVE_TOKEN_GCM';
export const DELETE_TOKEN_GCM = 'DELETE_TOKEN_GCM';
export const SAVE_TOKEN_PUSH = 'SAVE_TOKEN_PUSH';
export const DELETE_TOKEN_PUSH = 'DELETE_TOKEN_PUSH';

export const EVENT_REALM_EMOJI_UPDATE = 'EVENT_REALM_EMOJI_UPDATE';

Expand Down
2 changes: 1 addition & 1 deletion src/api/registerGCM.js → src/api/registerPush.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { apiPost } from './apiFetch';
export default async (auth: Auth, token: string) =>
apiPost(
auth,
'users/me/android_gcm_reg_id',
'users/me/android_push_reg_id',
res => res.api_key,
{
token,
Expand Down
15 changes: 15 additions & 0 deletions src/api/registerPush.ios.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* @flow */
import { Auth } from '../types';
import { apiPost } from './apiFetch';

export default async (auth: Auth, token: string) => {
apiPost(
auth,
'users/me/apns_device_token',
res => res,
{
token,
appid: 'com.zulip.Zulip'
},
);
};
11 changes: 11 additions & 0 deletions src/api/unregisterPush.android.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* @flow */
import { Auth } from '../types';
import { apiDelete } from './apiFetch';

export default (auth: Auth, token: string) =>
apiDelete(
auth,
'users/me/android_push_reg_id',
res => res.api_key,
{ token },
);
2 changes: 1 addition & 1 deletion src/api/unregisterGCM.js → src/api/unregisterPush.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { apiDelete } from './apiFetch';
export default (auth: Auth, token: string) =>
apiDelete(
auth,
'users/me/android_gcm_reg_id',
'users/me/apns_device_token',
res => res.api_key,
{ token },
);
2 changes: 1 addition & 1 deletion src/app/appReducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const initialState: AppState = {
isOnline: true,
isActive: true,
needsInitialFetch: false,
gcmToken: '',
pushToken: '',
eventQueueId: null,
};

Expand Down
Loading