diff --git a/android/app/agconnect-services.json b/android/app/agconnect-services.json index cfdaf83b..91aad2c7 100644 --- a/android/app/agconnect-services.json +++ b/android/app/agconnect-services.json @@ -1,6 +1,21 @@ { + "agcgw":{ + "backurl":"connect-drcn.hispace.hicloud.com", + "url":"connect-drcn.dbankcloud.cn", + "websocketbackurl":"connect-ws-drcn.hispace.dbankcloud.com", + "websocketurl":"connect-ws-drcn.hispace.dbankcloud.cn" + }, + "agcgw_all":{ + "CN":"connect-drcn.dbankcloud.cn", + "CN_back":"connect-drcn.hispace.hicloud.com", + "DE":"connect-dre.dbankcloud.cn", + "DE_back":"connect-dre.hispace.hicloud.com", + "RU":"connect-drru.dbankcloud.cn", + "RU_back":"connect-drru.hispace.hicloud.com", + "SG":"connect-dra.dbankcloud.cn", + "SG_back":"connect-dra.hispace.hicloud.com" + }, "client":{ - "appType":"1", "cp_id":"2640966000002322881", "product_id":"736430079244816567", "client_id":"563735388191982656", @@ -10,5 +25,50 @@ "api_key":"CgB6e3x9DJzMgRCmnT6dyUEkp6UsIfddb6l3w0ZEXzeiRMHEFi3400Z5fJ5qaHneU0OrAI/JRpk+DMGVs3QpUxlI", "package_name":"com.ejada.hmg" }, - "configuration_version":"1.0" -} \ No newline at end of file + "oauth_client":{ + "client_id":"102857389", + "client_type":1 + }, + "app_info":{ + "app_id":"102857389", + "package_name":"com.ejada.hmg" + }, + "service":{ + "analytics":{ + "collector_url":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn", + "collector_url_ru":"datacollector-drru.dt.hicloud.com,datacollector-drru.dt.dbankcloud.cn", + "collector_url_sg":"datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn", + "collector_url_de":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn", + "collector_url_cn":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn", + "resource_id":"p1", + "channel_id":"" + }, + "search":{ + "url":"https://search-drcn.cloud.huawei.com" + }, + "cloudstorage":{ + "storage_url":"https://agc-storage-drcn.platform.dbankcloud.cn" + }, + "ml":{ + "mlservice_url":"ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn" + } + }, + "region":"CN", + "configuration_version":"3.0", + "appInfos":[ + { + "package_name":"com.ejada.hmg", + "client":{ + "app_id":"102857389" + }, + "app_info":{ + "package_name":"com.ejada.hmg", + "app_id":"102857389" + }, + "oauth_client":{ + "client_type":1, + "client_id":"102857389" + } + } + ] +} diff --git a/android/app/build.gradle b/android/app/build.gradle index a465569d..65bb55fe 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -67,6 +67,7 @@ android { } release { signingConfig signingConfigs.config + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } staging { // Specifies a sorted list of fallback build types that the @@ -77,6 +78,15 @@ android { matchingFallbacks = ['debug', 'qa', 'release'] } } + + packagingOptions { + exclude 'META-INF/proguard/androidx-annotations.pro' + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } flutter { @@ -111,6 +121,7 @@ dependencies { implementation "com.opentok.android:opentok-android-sdk:2.19.1" + implementation 'com.facebook.stetho:stetho:1.5.1' implementation 'com.facebook.stetho:stetho-urlconnection:1.5.1' diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index 4ace459d..cfab1fd6 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -1,4 +1,27 @@ -keep class tvi.webrtc.** { *; } -keep class com.twilio.video.** { *; } -keep class com.twilio.common.** { *; } --keepattributes InnerClasses \ No newline at end of file +-keepattributes InnerClasses + +-keep class com.ejada.** { *; } +-keep class org.webrtc.** { *; } + +-ignorewarnings +-keepattributes *Annotation* +-keepattributes Exceptions +-keepattributes InnerClasses +-keepattributes Signature +-keep class com.hianalytics.android.**{*;} +-keep class com.huawei.updatesdk.**{*;} +-keep class com.huawei.hms.**{*;} + +## Flutter wrapper +-keep class io.flutter.app.** { *; } +-keep class io.flutter.plugin.** { *; } +-keep class io.flutter.util.** { *; } +-keep class io.flutter.view.** { *; } +-keep class io.flutter.** { *; } +-keep class io.flutter.plugins.** { *; } +-dontwarn io.flutter.embedding.** +-keep class com.huawei.hms.flutter.** { *; } +-repackageclasses \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index ba03f512..ebc7cc88 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -13,7 +13,7 @@ - + @@ -22,24 +22,18 @@ - - - - - + + + - - - - + + + + - + @@ -48,10 +42,12 @@ + android:screenOrientation="sensorPortrait" + android:label="Dr. Alhabib"> + + - - + + - - - - + + + - - + + - + - - + + + android:name="push_kit_auto_init_enabled" + android:value="true" /> + + + + + + + + + + + + + + + + Push Notification Background +Future backgroundMessageHandler(dynamic message) async{ + + fir.RemoteMessage message_; + if(message is h_push.RemoteMessage){ // if huawei remote message convert it to Firebase Remote Message + message_ = toFirebaseRemoteMessage(message); + } + + if (message_.data != null && message_.data['is_call'] == 'true') { + _incomingCall(message_.data); + return; + } + + + print("Background message is received, sending local notification."); + h_push.Push.localNotification({ + h_push.HMSLocalNotificationAttr.TITLE: 'Background Message', + h_push.HMSLocalNotificationAttr.MESSAGE: "By: BackgroundMessageHandler" + }); + +} +// Push Notification Background <--| + + + +RemoteMessage toFirebaseRemoteMessage(h_push.RemoteMessage message){ + final payload_data = jsonDecode(message.data); + final fire_message = RemoteMessage( + from: message.from, + collapseKey: message.collapseKey, + data: payload_data['data'], + messageId: message.messageId, + sentTime: DateTime.fromMillisecondsSinceEpoch(message.sentTime*1000), + ttl: message.ttl, + category: null, + messageType: message.type, + notification: RemoteNotification( + title: message.notification.title, + titleLocArgs: (message.notification.titleLocalizationArgs ?? []).map((e) => e.toString()).toList(), + titleLocKey: message.notification.titleLocalizationKey, + body: message.notification.body, + bodyLocArgs: (message.notification.bodyLocalizationArgs ?? []).map((e) => e.toString()).toList(), + bodyLocKey: message.notification.bodyLocalizationKey, + android: AndroidNotification( + channelId: message.notification.channelId, + clickAction: message.notification.clickAction, + color: message.notification.color, + count: null, + imageUrl: message.notification.imageUrl.path, + link: message.notification.link.path, + smallIcon: message.notification.icon, + sound: message.notification.sound, + ticker: message.notification.ticker, + tag: message.notification.tag, + ), + ) + ); + return fire_message; +} + +_incomingCall(Map data) async{ + LandingPage.incomingCallData = IncomingCallData.fromJson(data); + if(LandingPage.isOpenCallPage == false){ + LandingPage.isOpenCallPage = true; + final permited = await AppPermission.askVideoCallPermission(currentContext); + if(permited) + await NavigationService.navigateToPage(IncomingCall(incomingCallData: LandingPage.incomingCallData)); + LandingPage.isOpenCallPage = false; + } + await Future.delayed(Duration(milliseconds: 500)); + await AppSharedPreferences().remove('call_data'); +} + +class PushNotificationHandler{ + final BuildContext context; + static PushNotificationHandler _instance; + + PushNotificationHandler(this.context){ + PushNotificationHandler._instance = this; + } + + static PushNotificationHandler getInstance() => _instance; + + init() async{ + if (Platform.isIOS) { + final permission = await FirebaseMessaging.instance.requestPermission(); + if(permission.authorizationStatus == AuthorizationStatus.denied) + return; + } + + if(Platform.isAndroid && (await FlutterHmsGmsAvailability.isHmsAvailable)) { // 'Android HMS' (Handle Huawei Push_Kit Streams) + + h_push.Push.enableLogger(); + final result = await h_push.Push.setAutoInitEnabled(true); + + h_push.Push.onNotificationOpenedApp.listen((message){ + newMessage(toFirebaseRemoteMessage(message)); + }, onError: (e) => print(e.toString())); + + h_push.Push.onMessageReceivedStream.listen((message){ + newMessage(toFirebaseRemoteMessage(message)); + }, onError: (e) => print(e.toString())); + + + h_push.Push.getTokenStream.listen((token){ + onToken(token); + }, onError: (e) => print(e.toString())); + await h_push.Push.getToken(''); + + + h_push.Push.registerBackgroundMessageHandler(backgroundMessageHandler); + + }else{ // 'Android GMS or iOS' (Handle Firebase Messaging Streams) + + FirebaseMessaging.onMessage.listen((RemoteMessage message) async { + newMessage(message); + }); + + FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { + newMessage(message); + }); + + FirebaseMessaging.instance.onTokenRefresh.listen((fcm_token) { + onToken(fcm_token); + }); + + FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler); + + final fcmToken = await FirebaseMessaging.instance.getToken(); + if(fcmToken != null) + onToken(fcmToken); + } + } + + + newMessage(RemoteMessage remoteMessage){ + print('RemoteMessage.data:: ${remoteMessage.data}'); + if(remoteMessage.data['is_call'] == 'true' || remoteMessage.data['is_call'] == true) + _incomingCall(remoteMessage.data); + + } + + onToken(String token) async{ + print("Push Notification Token: " + token); + AppSharedPreferences().setString(PUSH_TOKEN, token); + DEVICE_TOKEN = token; + } + + onResume() async { + var call_data = await AppSharedPreferences().getObject('call_data'); + if(call_data != null){ + _incomingCall(call_data); + } + } + +} + +/* todo verify all functionality */ +// _firebaseMessaging.configure( +// // onMessage: (Map message) async { +// // // showDialog("onMessage: $message"); +// // print("onMessage: $message"); +// // print(message); +// // print(message['name']); +// // print(message['appointmentdate']); +// // +// // if (Platform.isIOS) { +// // if (message['is_call'] == "true") { +// // var route = ModalRoute.of(context); +// // +// // if (route != null) { +// // print(route.settings.name); +// // } +// //s +// // Map myMap = new Map.from(mesage); +// // print(myMap); +// // LandingPage.isOpenCallPage = true; +// // LandingPage.incomingCallData = IncomingCallData.fromJson(myMap); +// // if (!isPageNavigated) { +// // isPageNavigated = true; +// // Navigator.push(context, MaterialPageRoute(builder: (context) => IncomingCall(incomingCallData: LandingPage.incomingCallData))).then((value) { +// // isPageNavigated = false; +// // }); +// // } +// // } else { +// // print("Is Call Not Found iOS"); +// // } +// // } else { +// // print("Is Call Not Found iOS"); +// // } +// // +// // if (Platform.isAndroid) { +// // if (message['data'].containsKey("is_call")) { +// // var route = ModalRoute.of(context); +// // +// // if (route != null) { +// // print(route.settings.name); +// // } +// // +// // Map myMap = new Map.from(message['data']); +// // print(myMap); +// // if (LandingPage.isOpenCallPage) { +// // return; +// // } +// // LandingPage.isOpenCallPage = true; +// // LandingPage.incomingCallData = IncomingCallData.fromJson(myMap); +// // if (!isPageNavigated) { +// // isPageNavigated = true; +// // Navigator.push(context, MaterialPageRoute(builder: (context) => IncomingCall(incomingCallData: LandingPage.incomingCallData))).then((value) { +// // Future.delayed(Duration(seconds: 5), () { +// // isPageNavigated = false; +// // }); +// // }); +// // } +// // } else { +// // print("Is Call Not Found Android"); +// // LocalNotification.getInstance().showNow(title: message['notification']['title'], subtitle: message['notification']['body']); +// // } +// // } else { +// // print("Is Call Not Found Android"); +// // } +// // }, +// onBackgroundMessage: Platform.isIOS ? null : myBackgroundMessageHandler, +// onLaunch: (Map message) async { +// print("onLaunch: $message"); +// // showDialog("onLaunch: $message"); +// }, +// onResume: (Map message) async { +// print("onResume: $message"); +// print(message); +// print(message['name']); +// print(message['appointmentdate']); +// +// // showDialog("onResume: $message"); +// +// if (Platform.isIOS) { +// if (message['is_call'] == "true") { +// var route = ModalRoute.of(context); +// +// if (route != null) { +// print(route.settings.name); +// } +// +// Map myMap = new Map.from(message); +// print(myMap); +// LandingPage.isOpenCallPage = true; +// LandingPage.incomingCallData = IncomingCallData.fromJson(myMap); +// if (!isPageNavigated) { +// isPageNavigated = true; +// Navigator.push(context, MaterialPageRoute(builder: (context) => IncomingCall(incomingCallData: LandingPage.incomingCallData))).then((value) { +// isPageNavigated = false; +// }); +// } +// } else { +// print("Is Call Not Found iOS"); +// } +// } else { +// print("Is Call Not Found iOS"); +// } +// }, +// ); \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index ef1b799f..a7996dc8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -57,6 +57,8 @@ dependencies: fluttertoast: ^8.0.8 firebase_messaging: ^11.1.0 firebase_analytics: ^8.3.4 + + # Progress bar progress_hud_v2: ^2.0.0 percent_indicator: ^3.4.0 @@ -85,7 +87,10 @@ dependencies: charts_flutter: ^0.12.0 google_maps_flutter: ^2.1.1 + + # Huawei huawei_map: ^6.0.1+304 + huawei_push: ^5.3.0+304 # Qr code Scanner TODO fix it # barcode_scanner: ^1.0.1