Skip to content

Commit

Permalink
Feat/OK-11407, OK-11411 push notification (OneKeyHQ#1333)
Browse files Browse the repository at this point in the history
* feat: push-notification UI

fix: first ask notification permission bug

feat: access jpush for ios

feat: OK-11407, OK-11411 push notification

* fix: desktop build faild

* fix: lint

* feat: use NotificationProvider for push notification init

* feat: add jpush env

* feat: use enableTestFiatEndpoint for push notification
  • Loading branch information
qwang1113 authored Aug 18, 2022
1 parent 91e7d19 commit 9531ca2
Show file tree
Hide file tree
Showing 29 changed files with 865 additions and 24 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ COVALENT_KEY=
CLOUNDINARY_NAME=
# runtime: moonpay API token
MOONPAY_KEY=
# Jpush
JPUSH_KEY=
JPUSH_CHANNEL=
# Will auto add and inject variable at CI job.Must give an empty line at end of this file.
34 changes: 22 additions & 12 deletions development/babelTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,27 @@ function normalizeConfig({ platform, config }) {
};
}

const transformInlineEnviromentVariables = [
'NODE_ENV',
'VERSION',
'BUILD_NUMBER',
'ONEKEY_PLATFORM',
'EXT_CHANNEL',
'ANDROID_CHANNEL',
'CLOUNDINARY_NAME',
'COVALENT_KEY',
'MOONPAY_KEY',
'HARDWARE_SDK_CONNECT_SRC',
];

if (platform === developmentConsts.platforms.app) {
transformInlineEnviromentVariables.push(
'JPUSH_KEY',
'JPUSH_CHANNEL',
'JPUSH_PRODUCTION',
);
}

config.plugins = [
...(config.plugins || []),
[
Expand All @@ -64,18 +85,7 @@ function normalizeConfig({ platform, config }) {
{
// *** ATTENTION: DO NOT expose any sensitive variable here ***
// *** like password, secretKey, etc. ***
'include': [
'NODE_ENV',
'VERSION',
'BUILD_NUMBER',
'ONEKEY_PLATFORM',
'EXT_CHANNEL',
'ANDROID_CHANNEL',
'CLOUNDINARY_NAME',
'COVALENT_KEY',
'MOONPAY_KEY',
'HARDWARE_SDK_CONNECT_SRC',
],
'include': transformInlineEnviromentVariables,
},
],
/*
Expand Down
6 changes: 5 additions & 1 deletion packages/app/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,11 @@ android {
versionCode appVersionCode
versionName appVersion
vectorDrawables.useSupportLibrary = true
manifestPlaceholders = [OTAUpdatesEnable: false]
manifestPlaceholders = [
OTAUpdatesEnable: false,
JPUSH_APPKEY: "JPUSH_KEY",
JPUSH_CHANNEL: "dev"
]
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()

if (isNewArchitectureEnabled()) {
Expand Down
8 changes: 7 additions & 1 deletion packages/app/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,11 @@
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
<meta-data
android:name="JPUSH_CHANNEL"
android:value="${JPUSH_CHANNEL}" />
<meta-data
android:name="JPUSH_APPKEY"
android:value="${JPUSH_APPKEY}" />
</application>
</manifest>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import android.webkit.WebView;

import io.csie.kudo.reactnative.v8.executor.V8ExecutorFactory;
import cn.jiguang.plugins.push.JPushModule;

public class MainApplication extends Application implements ReactApplication , ViewModelStoreOwner {
private final ViewModelStore mViewModelStore = new ViewModelStore();
Expand Down Expand Up @@ -120,6 +121,7 @@ public void onCreate() {

initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
ApplicationLifecycleDispatcher.onApplicationCreate(this);
JPushModule.registerActivityLifecycle(this);
}

@Override
Expand Down
6 changes: 6 additions & 0 deletions packages/app/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true")
project(":ReactAndroid").projectDir = file('../../../node_modules/react-native/ReactAndroid')
}
include ':lib-tabview'

include ':jpush-react-native'
project(':jpush-react-native').projectDir = new File(rootProject.projectDir, '../../../node_modules/jpush-react-native/android')
include ':jcore-react-native'
project(':jcore-react-native').projectDir = new File(rootProject.projectDir, '../../../node_modules/jcore-react-native/android')

87 changes: 87 additions & 0 deletions packages/app/ios/OneKeyWallet/AppDelegate.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#import "AppDelegate.h"
#import <RCTJPushModule.h>

#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
Expand All @@ -12,10 +13,32 @@
#import <Firebase/Firebase.h>
#endif

#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import <UserNotifications/UserNotifications.h>
#endif


@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// 添加开始
// JPush初始化配置
[JPUSHService setupWithOption:launchOptions appKey:@"JPUSH_KEY"
channel:@"dev" apsForProduction:NO];
// APNS
JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
if (@available(iOS 12.0, *)) {
entity.types = JPAuthorizationOptionAlert|JPAuthorizationOptionBadge|JPAuthorizationOptionSound|JPAuthorizationOptionProvidesAppNotificationSettings;
}
[JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
[launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey];
// 自定义消息
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
[defaultCenter addObserver:self selector:@selector(networkDidReceiveMessage:) name:kJPFNetworkDidReceiveMessageNotification object:nil];
// 地理围栏
[JPUSHService registerLbsGeofenceDelegate:self withLaunchOptions:launchOptions];
// 添加结束
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

#ifdef DEBUG
Expand Down Expand Up @@ -71,5 +94,69 @@ - (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull N
restorationHandler:restorationHandler];
}

//************************************************JPush start************************************************

//注册 APNS 成功并上报 DeviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[JPUSHService registerDeviceToken:deviceToken];
}

//iOS 7 APNS
- (void)application:(UIApplication *)application didReceiveRemoteNotification: (NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// iOS 10 以下 Required
NSLog(@"iOS 7 APNS");
[JPUSHService handleRemoteNotification:userInfo];
[[NSNotificationCenter defaultCenter] postNotificationName:J_APNS_NOTIFICATION_ARRIVED_EVENT object:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}

//iOS 10 前台收到消息
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler {
NSDictionary * userInfo = notification.request.content.userInfo;
if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
// Apns
NSLog(@"iOS 10 APNS 前台收到消息");
[JPUSHService handleRemoteNotification:userInfo];
[[NSNotificationCenter defaultCenter] postNotificationName:J_APNS_NOTIFICATION_ARRIVED_EVENT object:userInfo];
}
else {
// 本地通知 todo
NSLog(@"iOS 10 本地通知 前台收到消息");
[[NSNotificationCenter defaultCenter] postNotificationName:J_LOCAL_NOTIFICATION_ARRIVED_EVENT object:userInfo];
}
//需要执行这个方法,选择是否提醒用户,有 Badge、Sound、Alert 三种类型可以选择设置
completionHandler(UNNotificationPresentationOptionAlert);
}

//iOS 10 消息事件回调
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler: (void (^)(void))completionHandler {
NSDictionary * userInfo = response.notification.request.content.userInfo;
if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
// Apns
NSLog(@"iOS 10 APNS 消息事件回调");
[JPUSHService handleRemoteNotification:userInfo];
// 保障应用被杀死状态下,用户点击推送消息,打开app后可以收到点击通知事件
[[RCTJPushEventQueue sharedInstance]._notificationQueue insertObject:userInfo atIndex:0];
[[NSNotificationCenter defaultCenter] postNotificationName:J_APNS_NOTIFICATION_OPENED_EVENT object:userInfo];
}
else {
// 本地通知
NSLog(@"iOS 10 本地通知 消息事件回调");
// 保障应用被杀死状态下,用户点击推送消息,打开app后可以收到点击通知事件
[[RCTJPushEventQueue sharedInstance]._localNotificationQueue insertObject:userInfo atIndex:0];
[[NSNotificationCenter defaultCenter] postNotificationName:J_LOCAL_NOTIFICATION_OPENED_EVENT object:userInfo];
}
// 系统要求执行这个方法
completionHandler();
}

//自定义消息
- (void)networkDidReceiveMessage:(NSNotification *)notification {
NSDictionary * userInfo = [notification userInfo];
[[NSNotificationCenter defaultCenter] postNotificationName:J_CUSTOM_NOTIFICATION_EVENT object:userInfo];
}

//************************************************JPush end************************************************

@end

18 changes: 18 additions & 0 deletions packages/app/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ PODS:
- EXMediaLibrary (14.1.0):
- ExpoModulesCore
- React-Core
- EXNotifications (0.15.4):
- ExpoModulesCore
- Expo (45.0.5):
- ExpoModulesCore
- ExpoClipboard (3.0.1):
Expand Down Expand Up @@ -154,6 +156,10 @@ PODS:
- GoogleUtilities/Logger
- GTMSessionFetcher/Core (1.7.2)
- IQKeyboardManagerSwift (6.5.4)
- JCore (2.0.3):
- React
- JPush (2.9.2):
- React
- JXCategoryView (1.6.1)
- JXPagingView/Pager (2.1.2)
- libwebp (1.2.3):
Expand Down Expand Up @@ -628,6 +634,7 @@ DEPENDENCIES:
- EXLocalAuthentication (from `../../../node_modules/expo-local-authentication/ios`)
- EXLocation (from `../../../node_modules/expo-location/ios`)
- EXMediaLibrary (from `../../../node_modules/expo-media-library/ios`)
- EXNotifications (from `../../../node_modules/expo-notifications/ios`)
- Expo (from `../../../node_modules/expo/ios`)
- ExpoClipboard (from `../../../node_modules/expo-clipboard/ios`)
- ExpoHaptics (from `../../../node_modules/expo-haptics/ios`)
Expand All @@ -641,6 +648,8 @@ DEPENDENCIES:
- FBLazyVector (from `../../../node_modules/react-native/Libraries/FBLazyVector`)
- FBReactNativeSpec (from `../../../node_modules/react-native/React/FBReactNativeSpec`)
- glog (from `../../../node_modules/react-native/third-party-podspecs/glog.podspec`)
- JCore (from `../../../node_modules/jcore-react-native`)
- JPush (from `../../../node_modules/jpush-react-native`)
- JXCategoryView
- JXPagingView/Pager
- lottie-ios (from `../../../node_modules/lottie-ios`)
Expand Down Expand Up @@ -765,6 +774,8 @@ EXTERNAL SOURCES:
:path: "../../../node_modules/expo-location/ios"
EXMediaLibrary:
:path: "../../../node_modules/expo-media-library/ios"
EXNotifications:
:path: "../../../node_modules/expo-notifications/ios"
Expo:
:path: "../../../node_modules/expo/ios"
ExpoClipboard:
Expand All @@ -791,6 +802,10 @@ EXTERNAL SOURCES:
:path: "../../../node_modules/react-native/React/FBReactNativeSpec"
glog:
:podspec: "../../../node_modules/react-native/third-party-podspecs/glog.podspec"
JCore:
:path: "../../../node_modules/jcore-react-native"
JPush:
:path: "../../../node_modules/jpush-react-native"
lottie-ios:
:path: "../../../node_modules/lottie-ios"
lottie-react-native:
Expand Down Expand Up @@ -920,6 +935,7 @@ SPEC CHECKSUMS:
EXLocalAuthentication: 7f37b242eae73f9acf111d39bdee3f1379e68902
EXLocation: f9811c5a78e07894429e7e0620b30f2395564fc0
EXMediaLibrary: 84cddf988a089e28070790438caf58d8b265b37a
EXNotifications: 297bb555bbd26fd7aa8ff3bf7e724d4d65f7e895
Expo: b9fff0a1eac0f424fc68ea49b4347fb308e52e17
ExpoClipboard: e2dda22be0524595a5eeead51665f60729829123
ExpoHaptics: ad58ec96a25e57579c14a47c7d71f0de0de8656a
Expand Down Expand Up @@ -948,6 +964,8 @@ SPEC CHECKSUMS:
GoogleUtilitiesComponents: 679b2c881db3b615a2777504623df6122dd20afe
GTMSessionFetcher: 5595ec75acf5be50814f81e9189490412bad82ba
IQKeyboardManagerSwift: 2dde0fc70110e8eac7ccce2a46fdbec6a850b414
JCore: fd3304b14f32fdb8cc3999c58d4d8366fb50085f
JPush: 0f2e50224c69fe5c2d6385776ed8c84e1b0727bd
JXCategoryView: 7b1ee69ede4843c581688afe84d0f047723262f2
JXPagingView: 90924b364a2ff7e94db534fad1fa50925ff69ee4
libwebp: 60305b2e989864154bd9be3d772730f08fc6a59c
Expand Down
4 changes: 3 additions & 1 deletion packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@
"redux-flipper": "^2.0.2",
"text-encoding": "^0.7.0",
"v8-android-jit": "^10.100.1",
"vision-camera-code-scanner": "^0.2.0"
"vision-camera-code-scanner": "^0.2.0",
"jcore-react-native": "2.0.3",
"jpush-react-native": "2.9.2"
},
"devDependencies": {
"@babel/core": "^7.15.8",
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/src-electron/preload.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ipcRenderer } from 'electron';
import keytar from 'keytar';

export type PrefType = 'camera' | 'bluetooth' | 'location';
export type PrefType = 'camera' | 'bluetooth' | 'location' | 'notification';
export type DesktopAPI = {
hello: string;
arch: string;
Expand Down
6 changes: 6 additions & 0 deletions packages/engine/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import {
getEVMNetworkToCreate,
parseNetworkId,
} from './managers/network';
import { syncPushNotificationConfig } from './managers/notification';
import {
fetchTokenDetail,
fetchTokenTop2000,
Expand Down Expand Up @@ -2304,6 +2305,11 @@ class Engine {
this.validator.dbApi = this.dbApi;
return Promise.resolve();
}

@backgroundMethod()
async syncPushNotificationConfig() {
return syncPushNotificationConfig();
}
}

export { Engine };
49 changes: 49 additions & 0 deletions packages/engine/src/managers/notification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import axios from 'axios';

import { appSelector } from '@onekeyhq/kit/src/store';
import { SettingsState } from '@onekeyhq/kit/src/store/reducers/settings';
import { getDefaultLocale } from '@onekeyhq/kit/src/utils/locale';
import debugLogger from '@onekeyhq/shared/src/logger/debugLogger';

import { getFiatEndpoint } from '../endpoint';

type PartialNotificationType = Partial<SettingsState['pushNotification']> & {
instanceId?: string;
};

async function fetchData<T>(
path: string,
body: Record<string, unknown> = {},
fallback: T,
): Promise<T> {
const endpoint = getFiatEndpoint();
const apiUrl = `${endpoint}${path}`;
try {
debugLogger.common.debug(`syncPushNotificationConfig`, {
apiUrl,
body,
});
const { data } = await axios.put<T>(apiUrl, body);
return data;
} catch (error) {
debugLogger.common.error(`fetch ${apiUrl} error`);
return fallback;
}
}

export const syncPushNotificationConfig =
async (): Promise<PartialNotificationType> => {
const config: PartialNotificationType = appSelector((state) => ({
...(state?.settings?.pushNotification || {}),
instanceId: state?.settings?.instanceId,
locale:
state.settings.locale === 'system'
? getDefaultLocale()
: state.settings.locale,
currency: state.settings.selectedFiatMoneySymbol,
}));
if (!config.instanceId || !config.registrationId) {
return {};
}
return fetchData('/notification/config', config, {});
};
3 changes: 2 additions & 1 deletion packages/kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
"swr": "^1.1.2",
"url-parse": "^1.5.10",
"vision-camera-code-scanner": "^0.2.0",
"zbar.wasm": "^2.1.1"
"zbar.wasm": "^2.1.1",
"expo-notifications": "~0.15.4"
},
"scripts": {
"lint": "tsc --noEmit && eslint . --ext .ts,.tsx",
Expand Down
Loading

0 comments on commit 9531ca2

Please sign in to comment.