diff --git a/android/build.gradle b/android/build.gradle
index de0db35f9d7c22a6d8a179f04fc39dafa1275214..2fdb45b1175a62a8df25a1d48d5d609484230472 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -20,8 +20,8 @@ android {
dependencies {
// Google's GCM.
- compile 'com.google.android.gms:play-services-gcm:15.0.1'
-
+// compile 'com.google.android.gms:play-services-gcm:15.0.1'
+ compile "com.google.firebase:firebase-messaging:17.3.0"
compile 'com.facebook.react:react-native:+'
testCompile 'junit:junit:4.12'
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index 14334752383c271cef67a598c6282e09dcbd8885..ffef75f236e30d1e2d4b99280dcb04964b70afd9 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -21,39 +21,16 @@
-->
-
-
-
-
-
-
-
-
-
+ android:name=".gcm.FcmInstanceIdListenerService">
-
-
-
-
-
-
-
+
+
+
diff --git a/android/src/main/java/com/wix/reactnativenotifications/RNNotificationsModule.java b/android/src/main/java/com/wix/reactnativenotifications/RNNotificationsModule.java
index 33a13bf94c95b8070bcb9cdd65fcceefa1e8c2ce..6588ce058b013f2ee0a87eec381377f3752a11f2 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/RNNotificationsModule.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/RNNotificationsModule.java
@@ -8,6 +8,7 @@ import android.os.Bundle;
import android.support.v4.app.NotificationManagerCompat;
import android.util.Log;
+import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
@@ -23,20 +24,21 @@ import com.wix.reactnativenotifications.core.notification.PushNotification;
import com.wix.reactnativenotifications.core.notification.PushNotificationProps;
import com.wix.reactnativenotifications.core.notificationdrawer.IPushNotificationsDrawer;
import com.wix.reactnativenotifications.core.notificationdrawer.PushNotificationsDrawer;
-import com.wix.reactnativenotifications.gcm.GcmInstanceIdRefreshHandlerService;
+import com.wix.reactnativenotifications.gcm.FcmInstanceIdRefreshHandlerService;
+
+import com.google.firebase.FirebaseApp;
import static com.wix.reactnativenotifications.Defs.LOGTAG;
-public class RNNotificationsModule extends ReactContextBaseJavaModule implements AppLifecycleFacade.AppVisibilityListener, Application.ActivityLifecycleCallbacks {
+public class RNNotificationsModule extends ReactContextBaseJavaModule implements ActivityEventListener {
public RNNotificationsModule(Application application, ReactApplicationContext reactContext) {
super(reactContext);
-
if (AppLifecycleFacadeHolder.get() instanceof ReactAppLifecycleFacade) {
((ReactAppLifecycleFacade) AppLifecycleFacadeHolder.get()).init(reactContext);
}
- AppLifecycleFacadeHolder.get().addVisibilityListener(this);
- application.registerActivityLifecycleCallbacks(this);
+
+ reactContext.addActivityEventListener(this);
}
@Override
@@ -47,16 +49,32 @@ public class RNNotificationsModule extends ReactContextBaseJavaModule implements
@Override
public void initialize() {
Log.d(LOGTAG, "Native module init");
- startGcmIntentService(GcmInstanceIdRefreshHandlerService.EXTRA_IS_APP_INIT);
+ startGcmIntentService(FcmInstanceIdRefreshHandlerService.EXTRA_IS_APP_INIT);
final IPushNotificationsDrawer notificationsDrawer = PushNotificationsDrawer.get(getReactApplicationContext().getApplicationContext());
notificationsDrawer.onAppInit();
}
+ @Override
+ public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
+
+ }
+
+ @Override
+ public void onNewIntent(Intent intent) {
+ Bundle notificationData = intent.getExtras();
+ if (notificationData != null) {
+ final IPushNotification notification = PushNotification.get(getReactApplicationContext().getApplicationContext(), notificationData);
+ if (notification != null) {
+ notification.onOpened();
+ }
+ }
+ }
+
@ReactMethod
public void refreshToken() {
Log.d(LOGTAG, "Native method invocation: refreshToken()");
- startGcmIntentService(GcmInstanceIdRefreshHandlerService.EXTRA_MANUAL_REFRESH);
+ startGcmIntentService(FcmInstanceIdRefreshHandlerService.EXTRA_MANUAL_REFRESH);
}
@ReactMethod
@@ -96,49 +114,9 @@ public class RNNotificationsModule extends ReactContextBaseJavaModule implements
promise.resolve(new Boolean(hasPermission));
}
- @Override
- public void onAppVisible() {
- final IPushNotificationsDrawer notificationsDrawer = PushNotificationsDrawer.get(getReactApplicationContext().getApplicationContext());
- notificationsDrawer.onAppVisible();
- }
-
- @Override
- public void onAppNotVisible() {
- }
-
- @Override
- public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
- final IPushNotificationsDrawer notificationsDrawer = PushNotificationsDrawer.get(getReactApplicationContext().getApplicationContext());
- notificationsDrawer.onNewActivity(activity);
- }
-
- @Override
- public void onActivityStarted(Activity activity) {
- }
-
- @Override
- public void onActivityResumed(Activity activity) {
- }
-
- @Override
- public void onActivityPaused(Activity activity) {
- }
-
- @Override
- public void onActivityStopped(Activity activity) {
- }
-
- @Override
- public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
- }
-
- @Override
- public void onActivityDestroyed(Activity activity) {
- }
-
protected void startGcmIntentService(String extraFlag) {
final Context appContext = getReactApplicationContext().getApplicationContext();
- final Intent tokenFetchIntent = new Intent(appContext, GcmInstanceIdRefreshHandlerService.class);
+ final Intent tokenFetchIntent = new Intent(appContext, FcmInstanceIdRefreshHandlerService.class);
tokenFetchIntent.putExtra(extraFlag, true);
appContext.startService(tokenFetchIntent);
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/RNNotificationsPackage.java b/android/src/main/java/com/wix/reactnativenotifications/RNNotificationsPackage.java
index 417e12b6417c2d4c40799c662047c0cd3f8e6402..d280fe7ebc6c2902fbc57e1f1308a583bfe67027 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/RNNotificationsPackage.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/RNNotificationsPackage.java
@@ -1,22 +1,41 @@
package com.wix.reactnativenotifications;
+import android.app.Activity;
import android.app.Application;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
+import com.google.firebase.FirebaseApp;
+import com.wix.reactnativenotifications.core.AppLifecycleFacade;
+import com.wix.reactnativenotifications.core.AppLifecycleFacadeHolder;
+import com.wix.reactnativenotifications.core.notification.IPushNotification;
+import com.wix.reactnativenotifications.core.notification.PushNotification;
+import com.wix.reactnativenotifications.core.notificationdrawer.IPushNotificationsDrawer;
+import com.wix.reactnativenotifications.core.notificationdrawer.PushNotificationsDrawer;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
-public class RNNotificationsPackage implements ReactPackage {
+import static com.wix.reactnativenotifications.Defs.LOGTAG;
+
+public class RNNotificationsPackage implements ReactPackage, AppLifecycleFacade.AppVisibilityListener, Application.ActivityLifecycleCallbacks {
private final Application mApplication;
public RNNotificationsPackage(Application application) {
mApplication = application;
+ FirebaseApp.initializeApp(application.getApplicationContext());
+
+ AppLifecycleFacadeHolder.get().addVisibilityListener(this);
+ application.registerActivityLifecycleCallbacks(this);
}
@Override
@@ -28,4 +47,55 @@ public class RNNotificationsPackage implements ReactPackage {
public List createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
+
+ @Override
+ public void onAppVisible() {
+ final IPushNotificationsDrawer notificationsDrawer = PushNotificationsDrawer.get(mApplication.getApplicationContext());
+ notificationsDrawer.onAppVisible();
+ }
+
+ @Override
+ public void onAppNotVisible() {
+ }
+
+ @Override
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+ final IPushNotificationsDrawer notificationsDrawer = PushNotificationsDrawer.get(mApplication.getApplicationContext());
+ notificationsDrawer.onNewActivity(activity);
+
+ Intent intent = activity.getIntent();
+ if (intent != null) {
+ Bundle notificationData = intent.getExtras();
+ if (notificationData != null) {
+ final IPushNotification pushNotification = PushNotification.get(mApplication.getApplicationContext(), notificationData);
+ if (pushNotification != null) {
+ pushNotification.onOpened();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onActivityStarted(Activity activity) {
+ }
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+ }
+
+ @Override
+ public void onActivityPaused(Activity activity) {
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ }
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java b/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
index 3ea5eb3d0527f734ffb89969939dacc210883794..ba5e1c3238f22000b3127ba53f9a54120a7b2b76 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
@@ -43,6 +43,10 @@ public class PushNotification implements IPushNotification {
};
public static IPushNotification get(Context context, Bundle bundle) {
+ if (verifyNotificationBundle(bundle) == false) {
+ return null;
+ }
+
Context appContext = context.getApplicationContext();
if (appContext instanceof INotificationsApplication) {
return ((INotificationsApplication) appContext).getPushNotification(context, bundle, AppLifecycleFacadeHolder.get(), new AppLaunchHelper());
@@ -58,6 +62,14 @@ public class PushNotification implements IPushNotification {
mNotificationProps = createProps(bundle);
}
+ private static boolean verifyNotificationBundle(Bundle bundle) {
+ if (bundle.getString("google.message_id") != null) {
+ return true;
+ }
+
+ return false;
+ }
+
@Override
public void onReceived() throws InvalidNotificationException {
postNotification(null);
@@ -92,7 +104,6 @@ public class PushNotification implements IPushNotification {
protected void digestNotification() {
if (!mAppLifecycleFacade.isReactInitialized()) {
setAsInitialNotification();
- launchOrResumeApp();
return;
}
@@ -122,10 +133,6 @@ public class PushNotification implements IPushNotification {
protected void dispatchUponVisibility() {
mAppLifecycleFacade.addVisibilityListener(getIntermediateAppVisibilityListener());
-
- // Make the app visible so that we'll dispatch the notification opening when visibility changes to 'true' (see
- // above listener registration).
- launchOrResumeApp();
}
protected AppVisibilityListener getIntermediateAppVisibilityListener() {
@@ -197,9 +204,4 @@ public class PushNotification implements IPushNotification {
private void notifyOpenedToJS() {
mJsIOHelper.sendEventToJS(NOTIFICATION_OPENED_EVENT_NAME, mNotificationProps.asBundle(), mAppLifecycleFacade.getRunningReactContext());
}
-
- protected void launchOrResumeApp() {
- final Intent intent = mAppLaunchHelper.getLaunchIntent(mContext);
- mContext.startActivity(intent);
- }
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmMessageHandlerService.java b/android/src/main/java/com/wix/reactnativenotifications/gcm/FcmInstanceIdListenerService.java
similarity index 63%
rename from android/src/main/java/com/wix/reactnativenotifications/gcm/GcmMessageHandlerService.java
rename to android/src/main/java/com/wix/reactnativenotifications/gcm/FcmInstanceIdListenerService.java
index f59665529429b87779fc37fe009f7505b30bc394..2456913ea09c931e99aa29550c9a61ac0c07c237 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmMessageHandlerService.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/gcm/FcmInstanceIdListenerService.java
@@ -3,16 +3,25 @@ package com.wix.reactnativenotifications.gcm;
import android.os.Bundle;
import android.util.Log;
-import com.google.android.gms.gcm.GcmListenerService;
+import com.google.firebase.messaging.FirebaseMessagingService;
+import com.google.firebase.messaging.RemoteMessage;
import com.wix.reactnativenotifications.core.notification.IPushNotification;
import com.wix.reactnativenotifications.core.notification.PushNotification;
+import java.util.Map;
+
import static com.wix.reactnativenotifications.Defs.LOGTAG;
-public class GcmMessageHandlerService extends GcmListenerService {
+/**
+ * Instance-ID + token refreshing handling service. Contacts the GCM to fetch the updated token.
+ *
+ * @author amitd
+ */
+public class FcmInstanceIdListenerService extends FirebaseMessagingService {
@Override
- public void onMessageReceived(String s, Bundle bundle) {
+ public void onMessageReceived(RemoteMessage message){
+ Bundle bundle = message.toIntent().getExtras();
Log.d(LOGTAG, "New message from GCM: " + bundle);
try {
diff --git a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmInstanceIdRefreshHandlerService.java b/android/src/main/java/com/wix/reactnativenotifications/gcm/FcmInstanceIdRefreshHandlerService.java
similarity index 74%
rename from android/src/main/java/com/wix/reactnativenotifications/gcm/GcmInstanceIdRefreshHandlerService.java
rename to android/src/main/java/com/wix/reactnativenotifications/gcm/FcmInstanceIdRefreshHandlerService.java
index 3aa7aa9dc8e248d2fa10ef93f3b296ec158e9b93..8270ad68e724f6463bee122fb17462c0a6a18adb 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmInstanceIdRefreshHandlerService.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/gcm/FcmInstanceIdRefreshHandlerService.java
@@ -3,18 +3,18 @@ package com.wix.reactnativenotifications.gcm;
import android.app.IntentService;
import android.content.Intent;
-public class GcmInstanceIdRefreshHandlerService extends IntentService {
+public class FcmInstanceIdRefreshHandlerService extends IntentService {
public static String EXTRA_IS_APP_INIT = "isAppInit";
public static String EXTRA_MANUAL_REFRESH = "doManualRefresh";
- public GcmInstanceIdRefreshHandlerService() {
- super(GcmInstanceIdRefreshHandlerService.class.getSimpleName());
+ public FcmInstanceIdRefreshHandlerService() {
+ super(FcmInstanceIdRefreshHandlerService.class.getSimpleName());
}
@Override
protected void onHandleIntent(Intent intent) {
- IGcmToken gcmToken = GcmToken.get(this);
+ IFcmToken gcmToken = FcmToken.get(this);
if (gcmToken == null) {
return;
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmToken.java b/android/src/main/java/com/wix/reactnativenotifications/gcm/FcmToken.java
similarity index 51%
rename from android/src/main/java/com/wix/reactnativenotifications/gcm/GcmToken.java
rename to android/src/main/java/com/wix/reactnativenotifications/gcm/FcmToken.java
index b11a6b5f4a6a89342d5d684bd0ed2d7950ec5991..44c8ec6dffe65f122ad21a4f51c2438fd2f11a31 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmToken.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/gcm/FcmToken.java
@@ -1,41 +1,38 @@
package com.wix.reactnativenotifications.gcm;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.support.annotation.NonNull;
import android.util.Log;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.core.DeviceEventManagerModule;
-import com.google.android.gms.gcm.GoogleCloudMessaging;
-import com.google.android.gms.iid.InstanceID;
+import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.firebase.iid.FirebaseInstanceId;
+import com.google.firebase.iid.InstanceIdResult;
-import static com.wix.reactnativenotifications.Defs.GCM_SENDER_ID_ATTR_NAME;
import static com.wix.reactnativenotifications.Defs.LOGTAG;
import static com.wix.reactnativenotifications.Defs.TOKEN_RECEIVED_EVENT_NAME;
-public class GcmToken implements IGcmToken {
+public class FcmToken implements IFcmToken {
final protected Context mAppContext;
protected static String sToken;
- protected GcmToken(Context appContext) {
+ protected FcmToken(Context appContext) {
if (!(appContext instanceof ReactApplication)) {
throw new IllegalStateException("Application instance isn't a react-application");
}
mAppContext = appContext;
}
- public static IGcmToken get(Context context) {
+ public static IFcmToken get(Context context) {
Context appContext = context.getApplicationContext();
if (appContext instanceof INotificationsGcmApplication) {
- return ((INotificationsGcmApplication) appContext).getGcmToken(context);
+ return ((INotificationsGcmApplication) appContext).getFcmToken(context);
}
- return new GcmToken(appContext);
+ return new FcmToken(appContext);
}
@Override
@@ -73,51 +70,14 @@ public class GcmToken implements IGcmToken {
}
protected void refreshToken() {
- try {
- sToken = getNewToken();
- } catch (Exception e) {
- Log.e(LOGTAG, "Failed to retrieve new token", e);
- return;
- }
-
- sendTokenToJS();
- }
-
- @NonNull
- protected String getNewToken() throws Exception {
- final InstanceID instanceId = InstanceID.getInstance(mAppContext);
- Log.d(LOGTAG, "GCM is refreshing token... instanceId=" + instanceId.getId());
-
- // TODO why is this needed?
- GoogleCloudMessaging.getInstance(mAppContext).close();
-
- try {
- final String registrationToken = instanceId.getToken(getSenderId(), GoogleCloudMessaging.INSTANCE_ID_SCOPE);
- Log.i(LOGTAG, "GCM has a new token: instanceId=" + instanceId.getId() + ", token=" + registrationToken);
- return registrationToken;
- } catch (Exception e) {
- throw new Exception("FATAL: Failed to fetch a fresh new token, instanceId=" + instanceId.getId(), e);
- }
- }
-
- protected String getSenderId() {
- final String senderId = getSenderIdFromManifest();
- if (senderId == null) {
- throw new IllegalStateException("Sender ID not found in manifest. Did you forget to add it as the value of a '"+GCM_SENDER_ID_ATTR_NAME+"' meta-data field?");
- }
- return senderId;
- }
-
- protected String getSenderIdFromManifest() {
- final ApplicationInfo appInfo;
- try {
- appInfo = mAppContext.getPackageManager().getApplicationInfo(mAppContext.getPackageName(), PackageManager.GET_META_DATA);
- return appInfo.metaData.getString(GCM_SENDER_ID_ATTR_NAME);
- } catch (PackageManager.NameNotFoundException e) {
- // Should REALLY never happen cause we're querying for our own package.
- Log.e(LOGTAG, "Failed to resolve sender ID from manifest", e);
- return null;
- }
+ FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener( new OnSuccessListener() {
+ @Override
+ public void onSuccess(InstanceIdResult instanceIdResult) {
+ sToken = instanceIdResult.getToken();
+ Log.i(LOGTAG, "FCM has a new token" + "=" + sToken);
+ sendTokenToJS();
+ }
+ });
}
protected void sendTokenToJS() {
diff --git a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmInstanceIdListenerService.java b/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmInstanceIdListenerService.java
deleted file mode 100644
index 933415f5cdc3b96b055c2a5e1c76208e914dc9b6..0000000000000000000000000000000000000000
--- a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmInstanceIdListenerService.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.wix.reactnativenotifications.gcm;
-
-import android.content.Intent;
-
-import com.google.android.gms.iid.InstanceIDListenerService;
-
-/**
- * Instance-ID + token refreshing handling service. Contacts the GCM to fetch the updated token.
- *
- * @author amitd
- */
-public class GcmInstanceIdListenerService extends InstanceIDListenerService {
-
- @Override
- public void onTokenRefresh() {
- // Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
- // Google recommends running this from an intent service.
- Intent intent = new Intent(this, GcmInstanceIdRefreshHandlerService.class);
- startService(intent);
- }
-}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/gcm/IGcmToken.java b/android/src/main/java/com/wix/reactnativenotifications/gcm/IFcmToken.java
similarity index 95%
rename from android/src/main/java/com/wix/reactnativenotifications/gcm/IGcmToken.java
rename to android/src/main/java/com/wix/reactnativenotifications/gcm/IFcmToken.java
index f324a591f64f0324be8132d41243c18b7b12f60f..9e75d39014c1a21bce7f854a3e0aa2d97abeaf0c 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/gcm/IGcmToken.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/gcm/IFcmToken.java
@@ -1,6 +1,6 @@
package com.wix.reactnativenotifications.gcm;
-public interface IGcmToken {
+public interface IFcmToken {
/**
* Handle an event where we've been notified of a that a fresh token is now available from Google.
diff --git a/android/src/main/java/com/wix/reactnativenotifications/gcm/INotificationsGcmApplication.java b/android/src/main/java/com/wix/reactnativenotifications/gcm/INotificationsGcmApplication.java
index 36f59f71cf2e4682d409c1fd21ac07a333d66a11..d318ecc4a9e1b78c99ce43875459c5d841426ad5 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/gcm/INotificationsGcmApplication.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/gcm/INotificationsGcmApplication.java
@@ -3,5 +3,5 @@ package com.wix.reactnativenotifications.gcm;
import android.content.Context;
public interface INotificationsGcmApplication {
- IGcmToken getGcmToken(Context context);
+ IFcmToken getFcmToken(Context context);
}
diff --git a/package.json b/package.json
index c070d13f5e4ba8f6461ce76379d92b45ac880712..4f3b9577e0668d25257a7ef5549305352a430117 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-native-notifications",
- "version": "1.1.24",
+ "version": "1.2.52",
"description": "Advanced Push Notifications (Silent, interactive notifications) for iOS & Android",
"author": "Lidan Hifi ",
"license": "MIT",