infobip-mobile-messaging-react-native-plugin 5.0.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ruby-version +1 -0
- package/Gemfile +4 -0
- package/Gemfile.lock +96 -0
- package/README.md +23 -14
- package/android/build.gradle +31 -34
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/android/src/main/AndroidManifest.xml +5 -4
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/Configuration.java +4 -1
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/ReactNativeMobileMessagingModule.java +44 -35
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/ReactNativeMobileMessagingPackage.java +0 -3
- package/index.js +68 -28
- package/infobip-mobile-messaging-react-native-plugin-6.0.0.tgz +0 -0
- package/infobip-mobile-messaging-react-native-plugin.podspec +3 -3
- package/ios/Cartfile +1 -1
- package/ios/Cartfile.resolved +1 -1
- package/ios/MobileMessagingPlugin/RNMobileMessaging.swift +10 -6
- package/ios/ReactNativeMobileMessaging.xcodeproj/project.pbxproj +1 -1
- package/package.json +4 -4
- package/.gitattributes +0 -1
- package/infobip-mobile-messaging-react-native-plugin-4.1.6.tgz +0 -0
package/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.7.4
|
package/Gemfile
ADDED
package/Gemfile.lock
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: https://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
CFPropertyList (3.0.5)
|
|
5
|
+
rexml
|
|
6
|
+
activesupport (6.1.5)
|
|
7
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
8
|
+
i18n (>= 1.6, < 2)
|
|
9
|
+
minitest (>= 5.1)
|
|
10
|
+
tzinfo (~> 2.0)
|
|
11
|
+
zeitwerk (~> 2.3)
|
|
12
|
+
addressable (2.8.0)
|
|
13
|
+
public_suffix (>= 2.0.2, < 5.0)
|
|
14
|
+
algoliasearch (1.27.5)
|
|
15
|
+
httpclient (~> 2.8, >= 2.8.3)
|
|
16
|
+
json (>= 1.5.1)
|
|
17
|
+
atomos (0.1.3)
|
|
18
|
+
claide (1.1.0)
|
|
19
|
+
cocoapods (1.11.3)
|
|
20
|
+
addressable (~> 2.8)
|
|
21
|
+
claide (>= 1.0.2, < 2.0)
|
|
22
|
+
cocoapods-core (= 1.11.3)
|
|
23
|
+
cocoapods-deintegrate (>= 1.0.5, < 2.0)
|
|
24
|
+
cocoapods-downloader (>= 1.6.2, < 2.0)
|
|
25
|
+
cocoapods-plugins (>= 1.0.0, < 2.0)
|
|
26
|
+
cocoapods-search (>= 1.0.0, < 2.0)
|
|
27
|
+
cocoapods-trunk (>= 1.4.0, < 2.0)
|
|
28
|
+
cocoapods-try (>= 1.1.0, < 2.0)
|
|
29
|
+
colored2 (~> 3.1)
|
|
30
|
+
escape (~> 0.0.4)
|
|
31
|
+
fourflusher (>= 2.3.0, < 3.0)
|
|
32
|
+
gh_inspector (~> 1.0)
|
|
33
|
+
molinillo (~> 0.8.0)
|
|
34
|
+
nap (~> 1.0)
|
|
35
|
+
ruby-macho (>= 1.0, < 3.0)
|
|
36
|
+
xcodeproj (>= 1.21.0, < 2.0)
|
|
37
|
+
cocoapods-core (1.11.3)
|
|
38
|
+
activesupport (>= 5.0, < 7)
|
|
39
|
+
addressable (~> 2.8)
|
|
40
|
+
algoliasearch (~> 1.0)
|
|
41
|
+
concurrent-ruby (~> 1.1)
|
|
42
|
+
fuzzy_match (~> 2.0.4)
|
|
43
|
+
nap (~> 1.0)
|
|
44
|
+
netrc (~> 0.11)
|
|
45
|
+
public_suffix (~> 4.0)
|
|
46
|
+
typhoeus (~> 1.0)
|
|
47
|
+
cocoapods-deintegrate (1.0.5)
|
|
48
|
+
cocoapods-downloader (1.5.1)
|
|
49
|
+
cocoapods-plugins (1.0.0)
|
|
50
|
+
nap
|
|
51
|
+
cocoapods-search (1.0.1)
|
|
52
|
+
cocoapods-trunk (1.6.0)
|
|
53
|
+
nap (>= 0.8, < 2.0)
|
|
54
|
+
netrc (~> 0.11)
|
|
55
|
+
cocoapods-try (1.2.0)
|
|
56
|
+
colored2 (3.1.2)
|
|
57
|
+
concurrent-ruby (1.1.9)
|
|
58
|
+
escape (0.0.4)
|
|
59
|
+
ethon (0.15.0)
|
|
60
|
+
ffi (>= 1.15.0)
|
|
61
|
+
ffi (1.15.5)
|
|
62
|
+
fourflusher (2.3.1)
|
|
63
|
+
fuzzy_match (2.0.4)
|
|
64
|
+
gh_inspector (1.1.3)
|
|
65
|
+
httpclient (2.8.3)
|
|
66
|
+
i18n (1.10.0)
|
|
67
|
+
concurrent-ruby (~> 1.0)
|
|
68
|
+
json (2.6.1)
|
|
69
|
+
minitest (5.15.0)
|
|
70
|
+
molinillo (0.8.0)
|
|
71
|
+
nanaimo (0.3.0)
|
|
72
|
+
nap (1.1.0)
|
|
73
|
+
netrc (0.11.0)
|
|
74
|
+
public_suffix (4.0.6)
|
|
75
|
+
rexml (3.2.5)
|
|
76
|
+
ruby-macho (2.5.1)
|
|
77
|
+
typhoeus (1.4.0)
|
|
78
|
+
ethon (>= 0.9.0)
|
|
79
|
+
tzinfo (2.0.4)
|
|
80
|
+
concurrent-ruby (~> 1.0)
|
|
81
|
+
xcodeproj (1.21.0)
|
|
82
|
+
CFPropertyList (>= 2.3.3, < 4.0)
|
|
83
|
+
atomos (~> 0.1.3)
|
|
84
|
+
claide (>= 1.0.2, < 2.0)
|
|
85
|
+
colored2 (~> 3.1)
|
|
86
|
+
nanaimo (~> 0.3.0)
|
|
87
|
+
rexml (~> 3.2.4)
|
|
88
|
+
zeitwerk (2.5.4)
|
|
89
|
+
PLATFORMS
|
|
90
|
+
ruby
|
|
91
|
+
DEPENDENCIES
|
|
92
|
+
cocoapods (~> 1.11, >= 1.11.2)
|
|
93
|
+
RUBY VERSION
|
|
94
|
+
ruby 2.7.4p191
|
|
95
|
+
BUNDLED WITH
|
|
96
|
+
2.2.27
|
package/README.md
CHANGED
|
@@ -10,17 +10,18 @@ The document describes library integration steps for your React Native project.
|
|
|
10
10
|
* [Initialization configuration](#initialization-configuration)
|
|
11
11
|
|
|
12
12
|
## Requirements
|
|
13
|
-
- node (
|
|
14
|
-
-
|
|
13
|
+
- node (v16.10.0 or higher)
|
|
14
|
+
- ruby (2.7.4)
|
|
15
|
+
- React Native (v0.68.0)
|
|
15
16
|
|
|
16
17
|
For iOS project:
|
|
17
|
-
- Xcode and Command Line Tools (13.1)
|
|
18
|
-
- CocoaPods (v1.
|
|
18
|
+
- Xcode and Command Line Tools (13.2.1)
|
|
19
|
+
- CocoaPods (v1.11.3)
|
|
19
20
|
- Minimum deployment target 11.0
|
|
20
21
|
|
|
21
22
|
For Android project:
|
|
22
|
-
- Android Studio (
|
|
23
|
-
- Gradle (
|
|
23
|
+
- Android Studio (Bumblebee | 2021.1.1)
|
|
24
|
+
- Gradle (v7.3.3)
|
|
24
25
|
- Minimum API Level: 21 (Android 5.0 - [Lollipop](https://developer.android.com/about/versions/lollipop))
|
|
25
26
|
|
|
26
27
|
## Quick start guide
|
|
@@ -39,10 +40,10 @@ This guide is designed to get you up and running with Mobile Messaging SDK plugi
|
|
|
39
40
|
- **iOS**
|
|
40
41
|
1. Add `use_frameworks!` into `/ios/Podfile` (required for Swift frameworks such as our Mobile Messaging SDK)
|
|
41
42
|
2. Run `pod install` from `/ios` folder (installs Mobile Messaging native SDK)
|
|
42
|
-
3. Import
|
|
43
|
+
3. Import following header `#import <MobileMessaging/MobileMessagingPluginApplicationDelegate.h>` and add `[MobileMessagingPluginApplicationDelegate install];` into `/ios/<ProjectName>/AppDelegate.m` (this is required for OS callbacks such as `didRegisterForRemoteNotifications` to be intercepted by native MobileMessaging SDK)
|
|
43
44
|
```objective-c
|
|
44
45
|
...
|
|
45
|
-
|
|
46
|
+
#import <MobileMessaging/MobileMessagingPluginApplicationDelegate.h>
|
|
46
47
|
|
|
47
48
|
@implementation AppDelegate
|
|
48
49
|
|
|
@@ -66,13 +67,21 @@ This guide is designed to get you up and running with Mobile Messaging SDK plugi
|
|
|
66
67
|
export PATH=$PATH:$ANDROID_HOME/tools/bin
|
|
67
68
|
export PATH=$PATH:$ANDROID_HOME/platform-tools
|
|
68
69
|
```
|
|
69
|
-
2. Add
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
2. Add 'com.google.gms:google-services' to `android/build.gradle` file
|
|
71
|
+
```groovy
|
|
72
|
+
buildscript {
|
|
73
|
+
...
|
|
74
|
+
dependencies {
|
|
75
|
+
...
|
|
76
|
+
//GMS Gradle plugin
|
|
77
|
+
classpath 'com.google.gms:google-services:4.3.10'
|
|
78
|
+
}
|
|
79
|
+
}
|
|
75
80
|
```
|
|
81
|
+
And add `apply plugin: 'com.google.gms.google-services'` at the end of your `android/app/build.gradle` in order to apply [Google Services Gradle Plugin](https://developers.google.com/android/guides/google-services-plugin)
|
|
82
|
+
3. Add a Firebase configuration file (google-services.json) as described in <a href="https://firebase.google.com/docs/android/setup#add-config-file" target="_blank">`Firebase documentation`</a>
|
|
83
|
+
> ### Notice:
|
|
84
|
+
> Check <a href="https://github.com/infobip/mobile-messaging-react-native-plugin/wiki/Applying-Firebase-configuration-in-MobileMessaging-SDK">Applying Firebase configuration in MobileMessaging SDK Guide</a> for alternatives.
|
|
76
85
|
|
|
77
86
|
## Initialization configuration
|
|
78
87
|
|
package/android/build.gradle
CHANGED
|
@@ -1,30 +1,19 @@
|
|
|
1
|
-
def defaultCompileSDKVersion =
|
|
2
|
-
def defaultBuildToolsVersion = '
|
|
1
|
+
def defaultCompileSDKVersion = 31
|
|
2
|
+
def defaultBuildToolsVersion = '31.0.0'
|
|
3
3
|
def defaultMinSDKVersion = 21
|
|
4
|
-
def defaultTargetSDKVersion =
|
|
4
|
+
def defaultTargetSDKVersion = 31
|
|
5
5
|
|
|
6
6
|
def getRootProjectProperty(property, fallback) {
|
|
7
7
|
rootProject.ext.has(property) ? rootProject.ext.get(property) : fallback
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
def overrideAndroidSupportLibsVersion = getRootProjectProperty('overrideAndroidSupportLibsVersion', '')
|
|
11
10
|
def overrideGmsVersion = getRootProjectProperty('overrideGmsVersion', '')
|
|
12
11
|
def overrideFirebaseVersion = getRootProjectProperty('overrideFirebaseVersion', '')
|
|
13
12
|
def overrideKotlinVersion = getRootProjectProperty('overrideKotlinVersion', '')
|
|
14
|
-
|
|
15
|
-
if (overrideAndroidSupportLibsVersion.empty || overrideAndroidSupportLibsVersion > "26") {
|
|
16
|
-
repositories {
|
|
17
|
-
mavenLocal()
|
|
18
|
-
mavenCentral()
|
|
19
|
-
maven {
|
|
20
|
-
url 'https://maven.google.com/'
|
|
21
|
-
name 'Google'
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
13
|
+
def withCryptorMigration = getRootProjectProperty('withCryptorMigration', false)
|
|
25
14
|
|
|
26
15
|
apply plugin: 'com.android.library'
|
|
27
|
-
apply plugin: 'maven'
|
|
16
|
+
apply plugin: 'maven-publish'
|
|
28
17
|
|
|
29
18
|
buildscript {
|
|
30
19
|
// The Android Gradle plugin is only required when opening the android folder stand-alone.
|
|
@@ -34,8 +23,14 @@ buildscript {
|
|
|
34
23
|
if (project == rootProject) {
|
|
35
24
|
repositories {
|
|
36
25
|
google()
|
|
37
|
-
|
|
38
|
-
mavenCentral
|
|
26
|
+
mavenLocal()
|
|
27
|
+
mavenCentral {
|
|
28
|
+
// We don't want to fetch react-native from Maven Central as there are
|
|
29
|
+
// older versions over there.
|
|
30
|
+
content {
|
|
31
|
+
excludeGroup "com.facebook.react"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
39
34
|
}
|
|
40
35
|
dependencies {
|
|
41
36
|
classpath 'com.android.tools.build:gradle:4.2+'
|
|
@@ -44,7 +39,7 @@ buildscript {
|
|
|
44
39
|
}
|
|
45
40
|
|
|
46
41
|
apply plugin: 'com.android.library'
|
|
47
|
-
apply plugin: 'maven'
|
|
42
|
+
apply plugin: 'maven-publish'
|
|
48
43
|
|
|
49
44
|
android {
|
|
50
45
|
compileSdkVersion getRootProjectProperty('compileSdkVersion', defaultCompileSDKVersion)
|
|
@@ -63,8 +58,6 @@ android {
|
|
|
63
58
|
|
|
64
59
|
repositories {
|
|
65
60
|
// ref: https://www.baeldung.com/maven-local-repository
|
|
66
|
-
mavenLocal()
|
|
67
|
-
mavenCentral()
|
|
68
61
|
maven {
|
|
69
62
|
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
|
70
63
|
url "$rootDir/../node_modules/react-native/android"
|
|
@@ -73,17 +66,25 @@ repositories {
|
|
|
73
66
|
// Android JSC is installed from npm
|
|
74
67
|
url "$rootDir/../node_modules/jsc-android/dist"
|
|
75
68
|
}
|
|
69
|
+
mavenCentral {
|
|
70
|
+
// We don't want to fetch react-native from Maven Central as there are
|
|
71
|
+
// older versions over there.
|
|
72
|
+
content {
|
|
73
|
+
excludeGroup "com.facebook.react"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
76
|
google()
|
|
77
|
-
|
|
77
|
+
mavenLocal()
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
dependencies {
|
|
81
|
-
def mmVersion = '
|
|
81
|
+
def mmVersion = '6.2.1'
|
|
82
82
|
|
|
83
83
|
implementation 'com.facebook.react:react-native:+'
|
|
84
84
|
implementation "androidx.annotation:annotation:1.1.0"
|
|
85
|
-
|
|
86
|
-
implementation '
|
|
85
|
+
|
|
86
|
+
implementation 'com.google.android.material:material:1.4.0'
|
|
87
|
+
implementation 'androidx.exifinterface:exifinterface:1.3.3'
|
|
87
88
|
|
|
88
89
|
implementation "com.infobip:infobip-mobile-messaging-android-resources:$mmVersion@aar"
|
|
89
90
|
implementation "com.infobip:infobip-mobile-messaging-android-chat-sdk:$mmVersion@aar"
|
|
@@ -95,10 +96,6 @@ dependencies {
|
|
|
95
96
|
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
if (!overrideAndroidSupportLibsVersion.empty) {
|
|
99
|
-
exclude group: 'com.android.support', module: 'support-v4'
|
|
100
|
-
exclude group: 'com.android.support', module: 'appcompat-v7'
|
|
101
|
-
}
|
|
102
99
|
if (!overrideGmsVersion.empty) {
|
|
103
100
|
exclude group: 'com.google.android.gms', module: 'play-services-location'
|
|
104
101
|
}
|
|
@@ -106,14 +103,14 @@ dependencies {
|
|
|
106
103
|
exclude group: 'com.google.firebase', module: 'firebase-messaging'
|
|
107
104
|
}
|
|
108
105
|
}
|
|
109
|
-
if (!overrideAndroidSupportLibsVersion.empty) {
|
|
110
|
-
implementation "com.android.support:support-v4:$overrideAndroidSupportLibsVersion"
|
|
111
|
-
implementation "com.android.support:appcompat-v7:$overrideAndroidSupportLibsVersion"
|
|
112
|
-
}
|
|
113
106
|
if (!overrideGmsVersion.empty) {
|
|
114
107
|
implementation "com.google.android.gms:play-services-location:$overrideGmsVersion"
|
|
115
108
|
}
|
|
116
109
|
if (!overrideFirebaseVersion.empty) {
|
|
117
110
|
implementation "com.google.firebase:firebase-messaging:$overrideFirebaseVersion"
|
|
118
111
|
}
|
|
119
|
-
|
|
112
|
+
|
|
113
|
+
if (withCryptorMigration.toBoolean()) {
|
|
114
|
+
implementation "com.infobip:infobip-mobile-messaging-android-cryptor-migration:$mmVersion@aar"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
Binary file
|
|
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|
|
3
3
|
distributionPath=wrapper/dists
|
|
4
4
|
zipStoreBase=GRADLE_USER_HOME
|
|
5
5
|
zipStorePath=wrapper/dists
|
|
6
|
-
distributionUrl=https\://services.gradle.org/distributions/gradle-
|
|
6
|
+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
|
@@ -39,8 +39,6 @@
|
|
|
39
39
|
android:exported="false"
|
|
40
40
|
android:permission="android.permission.BIND_JOB_SERVICE" />
|
|
41
41
|
|
|
42
|
-
<receiver android:name="org.infobip.mobile.messaging.notification.NotificationTapReceiver" />
|
|
43
|
-
|
|
44
42
|
<receiver
|
|
45
43
|
android:name="org.infobip.mobile.messaging.MobileMessagingConnectivityReceiver"
|
|
46
44
|
android:enabled="false"
|
|
@@ -50,8 +48,11 @@
|
|
|
50
48
|
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
|
|
51
49
|
</intent-filter>
|
|
52
50
|
</receiver>
|
|
53
|
-
<receiver android:name="org.infobip.mobile.messaging.interactive.notification.NotificationActionTapReceiver"
|
|
54
|
-
|
|
51
|
+
<receiver android:name="org.infobip.mobile.messaging.interactive.notification.NotificationActionTapReceiver"
|
|
52
|
+
android:exported="false"/>
|
|
53
|
+
|
|
54
|
+
<receiver android:name="org.infobip.reactlibrary.mobilemessaging.ReactNativeMobileMessagingModule$MessageEventReceiver"
|
|
55
|
+
android:exported="false">
|
|
55
56
|
<intent-filter>
|
|
56
57
|
<action android:name="org.infobip.mobile.messaging.MESSAGE_RECEIVED" />
|
|
57
58
|
<action android:name="org.infobip.mobile.messaging.NOTIFICATION_TAPPED" />
|
|
@@ -10,12 +10,15 @@ import java.util.Map;
|
|
|
10
10
|
|
|
11
11
|
import androidx.annotation.NonNull;
|
|
12
12
|
|
|
13
|
+
import com.google.firebase.FirebaseOptions;
|
|
14
|
+
|
|
13
15
|
class Configuration {
|
|
14
16
|
|
|
15
17
|
class AndroidConfiguration {
|
|
16
18
|
String notificationIcon;
|
|
17
19
|
boolean multipleNotifications;
|
|
18
20
|
String notificationAccentColor;
|
|
21
|
+
FirebaseOptions firebaseOptions;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
class PrivacySettings {
|
|
@@ -62,4 +65,4 @@ class Configuration {
|
|
|
62
65
|
|
|
63
66
|
return config;
|
|
64
67
|
}
|
|
65
|
-
}
|
|
68
|
+
}
|
|
@@ -31,6 +31,8 @@ import org.infobip.mobile.messaging.mobileapi.MobileMessagingError;
|
|
|
31
31
|
import org.infobip.mobile.messaging.mobileapi.Result;
|
|
32
32
|
import org.infobip.mobile.messaging.storage.MessageStore;
|
|
33
33
|
import org.infobip.mobile.messaging.storage.SQLiteMessageStore;
|
|
34
|
+
import org.infobip.mobile.messaging.util.Cryptor;
|
|
35
|
+
import org.infobip.mobile.messaging.util.DeviceInformation;
|
|
34
36
|
import org.infobip.mobile.messaging.util.PreferenceHelper;
|
|
35
37
|
import org.infobip.reactlibrary.mobilemessaging.datamappers.*;
|
|
36
38
|
import org.infobip.mobile.messaging.dal.bundle.MessageBundleMapper;
|
|
@@ -333,6 +335,24 @@ public class ReactNativeMobileMessagingModule extends ReactContextBaseJavaModule
|
|
|
333
335
|
notificationBuilder.withColor(color);
|
|
334
336
|
}
|
|
335
337
|
builder.withDisplayNotification(notificationBuilder.build());
|
|
338
|
+
|
|
339
|
+
if (configuration.android.firebaseOptions != null) {
|
|
340
|
+
builder.withFirebaseOptions(configuration.android.firebaseOptions);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Checking do we need to migrate data saved with old cryptor,
|
|
345
|
+
// if withCryptorMigration project ext property is set, ECBCryptorImpl class will exist.
|
|
346
|
+
Cryptor cryptor = null;
|
|
347
|
+
try {
|
|
348
|
+
Class cls = Class.forName("org.infobip.mobile.messaging.cryptor.ECBCryptorImpl");
|
|
349
|
+
cryptor = (Cryptor) cls.getDeclaredConstructor(String.class).newInstance(DeviceInformation.getDeviceID(context));
|
|
350
|
+
} catch (Exception e) {
|
|
351
|
+
Log.d(Utils.TAG, "Will not migrate cryptor :");
|
|
352
|
+
e.printStackTrace();
|
|
353
|
+
}
|
|
354
|
+
if (cryptor != null) {
|
|
355
|
+
builder.withCryptorMigration(cryptor);
|
|
336
356
|
}
|
|
337
357
|
|
|
338
358
|
builder.build(new MobileMessaging.InitListener() {
|
|
@@ -382,16 +402,14 @@ public class ReactNativeMobileMessagingModule extends ReactContextBaseJavaModule
|
|
|
382
402
|
messageStorageIntentFilter.addAction(action);
|
|
383
403
|
}
|
|
384
404
|
|
|
385
|
-
|
|
386
|
-
LocalBroadcastManager.getInstance(context).registerReceiver(messageStorageReceiver, messageStorageIntentFilter);
|
|
405
|
+
LocalBroadcastManager.getInstance(reactContext).registerReceiver(messageStorageReceiver, messageStorageIntentFilter);
|
|
387
406
|
broadcastReceiverRegistered = true;
|
|
388
407
|
}
|
|
389
408
|
|
|
390
409
|
private void unregisterBroadcastReceiver() {
|
|
391
410
|
if (!broadcastReceiverRegistered) return;
|
|
392
411
|
reactContext.unregisterReceiver(commonLibraryBroadcastReceiver);
|
|
393
|
-
|
|
394
|
-
LocalBroadcastManager.getInstance(context).unregisterReceiver(messageStorageReceiver);
|
|
412
|
+
LocalBroadcastManager.getInstance(reactContext).unregisterReceiver(messageStorageReceiver);
|
|
395
413
|
broadcastReceiverRegistered = false;
|
|
396
414
|
}
|
|
397
415
|
|
|
@@ -443,14 +461,13 @@ public class ReactNativeMobileMessagingModule extends ReactContextBaseJavaModule
|
|
|
443
461
|
|
|
444
462
|
@ReactMethod
|
|
445
463
|
public synchronized void defaultMessageStorage_find(String messageId, final Callback onSuccess, final Callback onError) throws JSONException {
|
|
446
|
-
|
|
447
|
-
MessageStore messageStore = MobileMessaging.getInstance(context).getMessageStore();
|
|
464
|
+
MessageStore messageStore = MobileMessaging.getInstance(reactContext).getMessageStore();
|
|
448
465
|
if (messageStore == null) {
|
|
449
466
|
onError.invoke(Utils.callbackError("Message store does not exist", null));
|
|
450
467
|
return;
|
|
451
468
|
}
|
|
452
469
|
|
|
453
|
-
for (Message m : messageStore.findAll(
|
|
470
|
+
for (Message m : messageStore.findAll(reactContext)) {
|
|
454
471
|
if (messageId.equals(m.getMessageId())) {
|
|
455
472
|
onSuccess.invoke(ReactNativeJson.convertJsonToMap(MessageJson.toJSON(m)));
|
|
456
473
|
return;
|
|
@@ -461,46 +478,43 @@ public class ReactNativeMobileMessagingModule extends ReactContextBaseJavaModule
|
|
|
461
478
|
|
|
462
479
|
@ReactMethod
|
|
463
480
|
public void defaultMessageStorage_findAll(final Callback onSuccess, final Callback onError) throws JSONException {
|
|
464
|
-
|
|
465
|
-
MessageStore messageStore = MobileMessaging.getInstance(context).getMessageStore();
|
|
481
|
+
MessageStore messageStore = MobileMessaging.getInstance(reactContext).getMessageStore();
|
|
466
482
|
if (messageStore == null) {
|
|
467
483
|
onError.invoke(Utils.callbackError("Message store does not exist", null));
|
|
468
484
|
return;
|
|
469
485
|
}
|
|
470
|
-
List<Message> messages = messageStore.findAll(
|
|
486
|
+
List<Message> messages = messageStore.findAll(reactContext);
|
|
471
487
|
onSuccess.invoke(ReactNativeJson.convertJsonToArray(MessageJson.toJSONArray(messages.toArray(new Message[messages.size()]))));
|
|
472
488
|
}
|
|
473
489
|
|
|
474
490
|
@ReactMethod
|
|
475
491
|
public synchronized void defaultMessageStorage_delete(String messageId, final Callback onSuccess, final Callback onError) throws JSONException {
|
|
476
|
-
|
|
477
|
-
MessageStore messageStore = MobileMessaging.getInstance(context).getMessageStore();
|
|
492
|
+
MessageStore messageStore = MobileMessaging.getInstance(reactContext).getMessageStore();
|
|
478
493
|
if (messageStore == null) {
|
|
479
494
|
onError.invoke(Utils.callbackError("Message store does not exist", null));
|
|
480
495
|
return;
|
|
481
496
|
}
|
|
482
497
|
|
|
483
498
|
List<Message> messagesToKeep = new ArrayList<Message>();
|
|
484
|
-
for (Message m : messageStore.findAll(
|
|
499
|
+
for (Message m : messageStore.findAll(reactContext)) {
|
|
485
500
|
if (messageId.equals(m.getMessageId())) {
|
|
486
501
|
continue;
|
|
487
502
|
}
|
|
488
503
|
messagesToKeep.add(m);
|
|
489
504
|
}
|
|
490
|
-
messageStore.deleteAll(
|
|
491
|
-
messageStore.save(
|
|
505
|
+
messageStore.deleteAll(reactContext);
|
|
506
|
+
messageStore.save(reactContext, messagesToKeep.toArray(new Message[messagesToKeep.size()]));
|
|
492
507
|
onSuccess.invoke();
|
|
493
508
|
}
|
|
494
509
|
|
|
495
510
|
@ReactMethod
|
|
496
511
|
public synchronized void defaultMessageStorage_deleteAll(final Callback onSuccess, final Callback onError) {
|
|
497
|
-
|
|
498
|
-
MessageStore messageStore = MobileMessaging.getInstance(context).getMessageStore();
|
|
512
|
+
MessageStore messageStore = MobileMessaging.getInstance(reactContext).getMessageStore();
|
|
499
513
|
if (messageStore == null) {
|
|
500
514
|
onError.invoke(Utils.callbackError("Message store does not exist", null));
|
|
501
515
|
return;
|
|
502
516
|
}
|
|
503
|
-
messageStore.deleteAll(
|
|
517
|
+
messageStore.deleteAll(reactContext);
|
|
504
518
|
onSuccess.invoke();
|
|
505
519
|
}
|
|
506
520
|
|
|
@@ -681,14 +695,13 @@ public class ReactNativeMobileMessagingModule extends ReactContextBaseJavaModule
|
|
|
681
695
|
|
|
682
696
|
@ReactMethod
|
|
683
697
|
public synchronized void defaultMessageStorage_find(String messageId, final Callback callback) throws JSONException {
|
|
684
|
-
|
|
685
|
-
MessageStore messageStore = MobileMessaging.getInstance(context).getMessageStore();
|
|
698
|
+
MessageStore messageStore = MobileMessaging.getInstance(reactContext).getMessageStore();
|
|
686
699
|
if (messageStore == null) {
|
|
687
700
|
callback.invoke();
|
|
688
701
|
return;
|
|
689
702
|
}
|
|
690
703
|
|
|
691
|
-
for (Message m : messageStore.findAll(
|
|
704
|
+
for (Message m : messageStore.findAll(reactContext)) {
|
|
692
705
|
if (messageId.equals(m.getMessageId())) {
|
|
693
706
|
callback.invoke(ReactNativeJson.convertJsonToMap(MessageJson.toJSON(m)));
|
|
694
707
|
return;
|
|
@@ -699,46 +712,43 @@ public class ReactNativeMobileMessagingModule extends ReactContextBaseJavaModule
|
|
|
699
712
|
|
|
700
713
|
@ReactMethod
|
|
701
714
|
public synchronized void defaultMessageStorage_findAll(final Callback callback) throws JSONException {
|
|
702
|
-
|
|
703
|
-
MessageStore messageStore = MobileMessaging.getInstance(context).getMessageStore();
|
|
715
|
+
MessageStore messageStore = MobileMessaging.getInstance(reactContext).getMessageStore();
|
|
704
716
|
if (messageStore == null) {
|
|
705
717
|
callback.invoke();
|
|
706
718
|
return;
|
|
707
719
|
}
|
|
708
|
-
List<Message> messages = messageStore.findAll(
|
|
720
|
+
List<Message> messages = messageStore.findAll(reactContext);
|
|
709
721
|
callback.invoke(ReactNativeJson.convertJsonToArray(MessageJson.toJSONArray(messages.toArray(new Message[messages.size()]))));
|
|
710
722
|
}
|
|
711
723
|
|
|
712
724
|
@ReactMethod
|
|
713
725
|
public synchronized void defaultMessageStorage_delete(String messageId, final Callback callback) throws JSONException {
|
|
714
|
-
|
|
715
|
-
MessageStore messageStore = MobileMessaging.getInstance(context).getMessageStore();
|
|
726
|
+
MessageStore messageStore = MobileMessaging.getInstance(reactContext).getMessageStore();
|
|
716
727
|
if (messageStore == null) {
|
|
717
728
|
callback.invoke();
|
|
718
729
|
return;
|
|
719
730
|
}
|
|
720
731
|
|
|
721
732
|
List<Message> messagesToKeep = new ArrayList<Message>();
|
|
722
|
-
for (Message m : messageStore.findAll(
|
|
733
|
+
for (Message m : messageStore.findAll(reactContext)) {
|
|
723
734
|
if (messageId.equals(m.getMessageId())) {
|
|
724
735
|
continue;
|
|
725
736
|
}
|
|
726
737
|
messagesToKeep.add(m);
|
|
727
738
|
}
|
|
728
|
-
messageStore.deleteAll(
|
|
729
|
-
messageStore.save(
|
|
739
|
+
messageStore.deleteAll(reactContext);
|
|
740
|
+
messageStore.save(reactContext, messagesToKeep.toArray(new Message[messagesToKeep.size()]));
|
|
730
741
|
callback.invoke();
|
|
731
742
|
}
|
|
732
743
|
|
|
733
744
|
@ReactMethod
|
|
734
745
|
public synchronized void defaultMessageStorage_deleteAll(final Callback callback) {
|
|
735
|
-
|
|
736
|
-
MessageStore messageStore = MobileMessaging.getInstance(context).getMessageStore();
|
|
746
|
+
MessageStore messageStore = MobileMessaging.getInstance(reactContext).getMessageStore();
|
|
737
747
|
if (messageStore == null) {
|
|
738
748
|
callback.invoke();
|
|
739
749
|
return;
|
|
740
750
|
}
|
|
741
|
-
messageStore.deleteAll(
|
|
751
|
+
messageStore.deleteAll(reactContext);
|
|
742
752
|
callback.invoke();
|
|
743
753
|
}
|
|
744
754
|
|
|
@@ -807,8 +817,7 @@ public class ReactNativeMobileMessagingModule extends ReactContextBaseJavaModule
|
|
|
807
817
|
@ReactMethod
|
|
808
818
|
void messageStorage_provideFindAllResult(ReadableArray result) {
|
|
809
819
|
|
|
810
|
-
|
|
811
|
-
MessageStoreAdapter.init(context);
|
|
820
|
+
MessageStoreAdapter.init(getReactApplicationContext());
|
|
812
821
|
|
|
813
822
|
try {
|
|
814
823
|
MessageStoreAdapter.messageStorage_findAllResults.addIfAbsent(ReactNativeJson.convertArrayToJson(result));
|
|
@@ -844,7 +853,7 @@ public class ReactNativeMobileMessagingModule extends ReactContextBaseJavaModule
|
|
|
844
853
|
reactContext.removeActivityEventListener(this);
|
|
845
854
|
|
|
846
855
|
GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();
|
|
847
|
-
int playServicesAvailabilityResult = googleApiAvailability.isGooglePlayServicesAvailable(
|
|
856
|
+
int playServicesAvailabilityResult = googleApiAvailability.isGooglePlayServicesAvailable(reactContext);
|
|
848
857
|
if (playServicesAvailabilityResult != ConnectionResult.SUCCESS) {
|
|
849
858
|
try {
|
|
850
859
|
showDialogForError(playServicesAvailabilityResult, successCallback, errorCallback);
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
package org.infobip.reactlibrary.mobilemessaging;
|
|
2
2
|
|
|
3
|
-
import android.widget.FrameLayout;
|
|
4
|
-
|
|
5
3
|
import androidx.annotation.NonNull;
|
|
6
4
|
|
|
7
5
|
import java.util.ArrayList;
|
|
@@ -13,7 +11,6 @@ import com.facebook.react.ReactPackage;
|
|
|
13
11
|
import com.facebook.react.bridge.NativeModule;
|
|
14
12
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
15
13
|
import com.facebook.react.uimanager.ViewManager;
|
|
16
|
-
import com.facebook.react.bridge.JavaScriptModule;
|
|
17
14
|
|
|
18
15
|
public class ReactNativeMobileMessagingPackage implements ReactPackage {
|
|
19
16
|
|
package/index.js
CHANGED
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
UIManager,
|
|
13
13
|
EmitterSubscription,
|
|
14
14
|
} from 'react-native';
|
|
15
|
+
import type {Rationale} from "react-native/Libraries/PermissionsAndroid/PermissionsAndroid";
|
|
16
|
+
import {Permission} from "react-native";
|
|
15
17
|
|
|
16
18
|
const { ReactNativeMobileMessaging, RNMMChat } = NativeModules;
|
|
17
19
|
|
|
@@ -146,8 +148,14 @@ class MobileMessaging {
|
|
|
146
148
|
* ios: {
|
|
147
149
|
* notificationTypes: ['alert', 'sound', 'badge'],
|
|
148
150
|
* forceCleanup: <Boolean>,
|
|
149
|
-
*
|
|
151
|
+
* logging: <Boolean>
|
|
150
152
|
* },
|
|
153
|
+
* android: {
|
|
154
|
+
* notificationIcon: <String>,
|
|
155
|
+
* multipleNotifications: <Boolean>,
|
|
156
|
+
* notificationAccentColor: <String>
|
|
157
|
+
* firebaseOptions: <Object>
|
|
158
|
+
* }
|
|
151
159
|
* privacySettings: {
|
|
152
160
|
* applicationCodePersistingDisabled: <Boolean>,
|
|
153
161
|
* userDataPersistingDisabled: <Boolean>,
|
|
@@ -242,33 +250,7 @@ class MobileMessaging {
|
|
|
242
250
|
|
|
243
251
|
config.reactNativePluginVersion = require('./package').version;
|
|
244
252
|
|
|
245
|
-
|
|
246
|
-
if (geofencingEnabled && Platform.OS === 'android') {
|
|
247
|
-
this.checkAndroidLocationPermission().then(granted => {
|
|
248
|
-
if (!granted) {
|
|
249
|
-
onError('Geofencing permission is not granted.');
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
ReactNativeMobileMessaging.init(config, onSuccess, onError);
|
|
253
|
-
})
|
|
254
|
-
} else {
|
|
255
|
-
ReactNativeMobileMessaging.init(config, onSuccess, onError);
|
|
256
|
-
}
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
async checkAndroidLocationPermission(): Promise<Boolean> {
|
|
260
|
-
const locationPermissionGranted = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION);
|
|
261
|
-
if (locationPermissionGranted) {
|
|
262
|
-
return true;
|
|
263
|
-
} else {
|
|
264
|
-
try {
|
|
265
|
-
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION);
|
|
266
|
-
return granted === PermissionsAndroid.RESULTS.GRANTED;
|
|
267
|
-
} catch (err) {
|
|
268
|
-
console.error('[RNMobileMessaging] Can\'t check android permission', err);
|
|
269
|
-
return false;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
253
|
+
ReactNativeMobileMessaging.init(config, onSuccess, onError);
|
|
272
254
|
};
|
|
273
255
|
|
|
274
256
|
/**
|
|
@@ -580,6 +562,64 @@ class MobileMessaging {
|
|
|
580
562
|
resetMessageCounter() {
|
|
581
563
|
RNMMChat.resetMessageCounter();
|
|
582
564
|
}
|
|
565
|
+
|
|
566
|
+
/* Geofencing permissions */
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* This is used for requesting Location permissions for Android
|
|
570
|
+
* @param rationale rationale to display if it's needed. Describing why this permissions required.
|
|
571
|
+
* Mobile Messaging SDK requires following permissions to be able to send geo targeted notifications, even if application is killed or on background.
|
|
572
|
+
* ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, ACCESS_BACKGROUND_LOCATION
|
|
573
|
+
* @return {Promise<boolean>}
|
|
574
|
+
*/
|
|
575
|
+
async requestAndroidPermissions(rationale?: Rationale): Promise<Boolean> {
|
|
576
|
+
const requiredPermissions = await this.requiredAndroidLocationPermissions();
|
|
577
|
+
if (requiredPermissions.length === 0) {
|
|
578
|
+
return Promise.resolve(true);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
return this.checkAndroidLocationPermission(requiredPermissions, rationale).then(granted => {
|
|
582
|
+
if (!granted) {
|
|
583
|
+
return Promise.resolve(false);
|
|
584
|
+
} else {
|
|
585
|
+
return this.requestAndroidPermissions(rationale);
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
async checkAndroidLocationPermission(permissions: Array<Permission>, rationale?: Rationale): Promise<Boolean> {
|
|
591
|
+
for (permission of permissions) {
|
|
592
|
+
const granted = await PermissionsAndroid.request(permission, rationale);
|
|
593
|
+
if (granted !== PermissionsAndroid.RESULTS.GRANTED) {
|
|
594
|
+
console.log("Permissions Result != Granted ", permission, granted);
|
|
595
|
+
return Promise.resolve(false);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
console.log("Permissions Result == Granted ");
|
|
599
|
+
return Promise.resolve(true);
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
async requiredAndroidLocationPermissions(): Promise<Array<Permission>> {
|
|
603
|
+
let permissions: Array<Permission> = [];
|
|
604
|
+
const fineLocationGranted = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION);
|
|
605
|
+
if (!fineLocationGranted) {
|
|
606
|
+
if (Platform.Version > 29) {
|
|
607
|
+
permissions = [PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION];
|
|
608
|
+
} else if (Platform.Version === 29) {
|
|
609
|
+
permissions = [PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, PermissionsAndroid.PERMISSIONS.ACCESS_BACKGROUND_LOCATION];
|
|
610
|
+
} else {
|
|
611
|
+
permissions = [PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION];
|
|
612
|
+
}
|
|
613
|
+
} else {
|
|
614
|
+
const backgroundLocationGranted = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.ACCESS_BACKGROUND_LOCATION);
|
|
615
|
+
if (!backgroundLocationGranted && Platform.Version > 29) {
|
|
616
|
+
permissions = [PermissionsAndroid.PERMISSIONS.ACCESS_BACKGROUND_LOCATION];
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
return Promise.resolve(permissions);
|
|
621
|
+
};
|
|
622
|
+
|
|
583
623
|
}
|
|
584
624
|
|
|
585
625
|
export class ChatView extends React.Component {
|
|
Binary file
|
|
@@ -19,8 +19,8 @@ Pod::Spec.new do |s|
|
|
|
19
19
|
s.requires_arc = true
|
|
20
20
|
|
|
21
21
|
s.dependency "React-Core"
|
|
22
|
-
s.dependency "MobileMessaging/Core", "9.2.
|
|
23
|
-
s.dependency "MobileMessaging/Geofencing", "9.2.
|
|
24
|
-
s.dependency "MobileMessaging/InAppChat", "9.2.
|
|
22
|
+
s.dependency "MobileMessaging/Core", "9.2.16"
|
|
23
|
+
s.dependency "MobileMessaging/Geofencing", "9.2.16"
|
|
24
|
+
s.dependency "MobileMessaging/InAppChat", "9.2.16"
|
|
25
25
|
|
|
26
26
|
end
|
package/ios/Cartfile
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
github "infobip/mobile-messaging-sdk-ios" "9.2.
|
|
1
|
+
github "infobip/mobile-messaging-sdk-ios" "9.2.16"
|
package/ios/Cartfile.resolved
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
github "infobip/mobile-messaging-sdk-ios" "9.2.
|
|
1
|
+
github "infobip/mobile-messaging-sdk-ios" "9.2.16"
|
|
@@ -70,18 +70,22 @@ class ReactNativeMobileMessaging: RCTEventEmitter {
|
|
|
70
70
|
return
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
let successCallback: RCTResponseSenderBlock = { [weak self] response in
|
|
74
|
+
RNMobileMessagingConfiguration.saveConfigToDefaults(rawConfig: config)
|
|
75
|
+
self?.isStarted = true
|
|
76
|
+
onSuccess(response)
|
|
77
|
+
}
|
|
78
|
+
|
|
73
79
|
let cachedConfigDict = RNMobileMessagingConfiguration.getRawConfigFromDefaults()
|
|
74
80
|
if let cachedConfigDict = cachedConfigDict, (config as NSDictionary) != (cachedConfigDict as NSDictionary)
|
|
75
81
|
{
|
|
76
82
|
stop()
|
|
77
|
-
start(configuration: configuration, onSuccess:
|
|
83
|
+
start(configuration: configuration, onSuccess: successCallback)
|
|
78
84
|
} else if cachedConfigDict == nil {
|
|
79
|
-
start(configuration: configuration, onSuccess:
|
|
85
|
+
start(configuration: configuration, onSuccess: successCallback)
|
|
86
|
+
} else {
|
|
87
|
+
successCallback(nil)
|
|
80
88
|
}
|
|
81
|
-
|
|
82
|
-
RNMobileMessagingConfiguration.saveConfigToDefaults(rawConfig: config)
|
|
83
|
-
isStarted = true
|
|
84
|
-
onSuccess(nil)
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
private func performEarlyStartIfPossible() {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "infobip-mobile-messaging-react-native-plugin",
|
|
3
3
|
"title": "Infobip Mobile Messaging React Native Plugin",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "6.0.0",
|
|
5
5
|
"description": "Infobip Mobile Messaging React Native Plugin",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"scripts": {
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"react": "^17.0.2",
|
|
37
|
-
"react-native": ">=0.
|
|
37
|
+
"react-native": ">=0.68.0 <1.0.x"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"metro-react-native-babel-preset": "^0.
|
|
40
|
+
"metro-react-native-babel-preset": "^0.67.0",
|
|
41
41
|
"react": "^17.0.2",
|
|
42
|
-
"react-native": "^0.
|
|
42
|
+
"react-native": "^0.68.0"
|
|
43
43
|
}
|
|
44
44
|
}
|
package/.gitattributes
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
*.pbxproj -text
|
|
Binary file
|