diff --git a/CHANGELOG.md b/CHANGELOG.md index 0212ae5602eb57fb4cc9dc680e6aaca5e93e83a7..988f3842ee574418cd7e59af40aec30fa5b5cde9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,11 @@ # Changelog +# 2.1.0 +## Added +* react-native 0.60 Support + +### Breaking Change +This version requires an additional installation step in order to identify the correct build flavor on android, as described in our [Installation docs](https://github.com/wix/react-native-notifications/blob/master/docs/installation.md#step-5-rnnotifications-and-react-native-version). + # 2.0.6 ## Fixed ### Android diff --git a/android/app/src/reactNative59/java/com/wix/reactnativenotifications/NotificationManagerCompatFacade.java b/android/app/src/reactNative59/java/com/wix/reactnativenotifications/NotificationManagerCompatFacade.java new file mode 100644 index 0000000000000000000000000000000000000000..f527a5d5a2a4d3d7178c1c3f9f338a9170e29a91 --- /dev/null +++ b/android/app/src/reactNative59/java/com/wix/reactnativenotifications/NotificationManagerCompatFacade.java @@ -0,0 +1,12 @@ + +package com.wix.reactnativenotifications; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.v4.app.NotificationManagerCompat; + +public abstract class NotificationManagerCompatFacade { + public static NotificationManagerCompat from(@NonNull Context context) { + return NotificationManagerCompat.from(context); + } +} diff --git a/android/app/src/reactNative60/java/com/wix/reactnativenotifications/NotificationManagerCompatFacade.java b/android/app/src/reactNative60/java/com/wix/reactnativenotifications/NotificationManagerCompatFacade.java new file mode 100644 index 0000000000000000000000000000000000000000..94ea1884c8d84d6d81efeb8ebe91dacf41d2622b --- /dev/null +++ b/android/app/src/reactNative60/java/com/wix/reactnativenotifications/NotificationManagerCompatFacade.java @@ -0,0 +1,12 @@ + +package com.wix.reactnativenotifications; + +import android.content.Context; +import androidx.annotation.NonNull; +import androidx.core.app.NotificationManagerCompat; + +public abstract class NotificationManagerCompatFacade { + public static NotificationManagerCompat from(@NonNull Context context) { + return NotificationManagerCompat.from(context); + } +} diff --git a/docs_old/installation.md b/docs_old/installation.md index 0bf20b4f8248978b95288b6ff2924b757fcbf83f..56c52d29a5ad758583c6f3853b268eba585883d7 100644 --- a/docs_old/installation.md +++ b/docs_old/installation.md @@ -119,3 +119,68 @@ dependencies { apply plugin: 'com.google.gms.google-services' ``` + +#### Step #5: RNNotifications and React Native version +This step is required only for `react-native-notifications` version `2.1.0` and above.
+ +react-native-notifications supports multiple React Native versions. Target the React Native version required by your project by specifying the RNN build flavor in `android/app/build.gradle`. + +```diff +android { + ... + defaultConfig { + applicationId "com.yourproject" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion ++ missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60" // See note below! + versionCode 1 + versionName "1.0" + ... + } + ... +} +``` + +!>Important note about `missingDimensionStrategy`
+>`reactNative59` - RN 0.59.x and below
+>`reactNative60` - RN 0.60.0 and above + +Now we need to instruct gradle how to build that flavor. To do so here two solutions: + +#### 5.1 Build app with gradle command + +**prefered solution** The RNNotification flavor you would like to build is specified in `app/build.gradle`. Therefore in order to compile only that flavor, instead of building your entire project using `./gradlew assembleDebug`, you should instruct gradle to build the app module: `./gradlew app:assembleDebug`. The easiest way is to add a package.json command to build and install your debug Android APK . + +``` +"scripts": { + ... + "android": "cd ./android && ./gradlew app:assembleDebug && ./gradlew installDebug" +} +``` + +Now run `npm run android` to build your application + +#### 5.2 Ignore other RNN flavors + +If you don't want to run `npm run android` and want to keep the default `react-native run-android` command, you need to specify to graddle to ignore the other flavors RNNotifications provides. + +To do so edit `android/build.gradle` and add: + +```diff ++subprojects { subproject -> ++ afterEvaluate { ++ if ((subproject.plugins.hasPlugin('android') || subproject.plugins.hasPlugin('android-library'))) { ++ android { ++ variantFilter { variant -> ++ def names = variant.flavors*.name ++ if (names.contains("reactNative59")) { ++ setIgnore(true) ++ } ++ } ++ } ++ } ++ } ++} +``` + +**Note**: As more build variants come available in the future, you will need to adjust the list (`names.contains("reactNative59")`). This is why we recommend the first solution. \ No newline at end of file diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 1d3591c8a4c9c29578c36c87f80c05a6aea3ee3f..ccb748f58cadc3512a20b15546b3872e25b71b7b 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -15,4 +15,7 @@ # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true \ No newline at end of file +# org.gradle.parallel=true + +android.useAndroidX=true +android.enableJetifier=true \ No newline at end of file diff --git a/example/android/myapplication/build.gradle b/example/android/myapplication/build.gradle index 2adc9ac534174701de6b4010d2e33c4eea8e810f..8fdb0b8d64264174a3733c91dc77d323ff69da86 100644 --- a/example/android/myapplication/build.gradle +++ b/example/android/myapplication/build.gradle @@ -23,6 +23,7 @@ android { ndk { abiFilters "armeabi-v7a", "x86" } + missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60" } buildTypes { release { @@ -34,17 +35,13 @@ android { sourceCompatibility 1.8 targetCompatibility 1.8 } -} - -configurations.all { - resolutionStrategy.eachDependency { DependencyResolveDetails details -> - def requested = details.requested - if (requested.group == 'com.android.support') { - details.useVersion "28.0.0" - } + packagingOptions { + pickFirst '**/libjsc.so' + pickFirst '**/libc++_shared.so' } } + configurations.all { resolutionStrategy { force 'org.webkit:android-jsc:r236355' @@ -52,12 +49,12 @@ configurations.all { } dependencies { -// compile fileTree(dir: 'libs', include: ['*.jar']) + implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.google.firebase:firebase-core:16.0.0' - implementation 'com.android.support:appcompat-v7:28.0.0' - implementation 'com.android.support:design:28.0.0' + implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'com.facebook.react:react-native:+' + implementation 'org.webkit:android-jsc-intl:+' implementation project(':react-native-notifications') testImplementation'junit:junit:4.12' diff --git a/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainActivity.java b/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainActivity.java index 30fedc6f2067447ea247a0871cf99b92736c7226..e600962f1b21b0dea383889c5738bf8326103a19 100644 --- a/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainActivity.java +++ b/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainActivity.java @@ -5,12 +5,6 @@ import com.facebook.react.ReactActivity; public class MainActivity extends ReactActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - @Override protected String getMainComponentName() { return "NotificationsExampleApp"; diff --git a/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainApplication.java b/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainApplication.java index 24c9cbce864af3ea4effa4830539ce9fba38a810..021e42a17b0d89c934852449b97e4271b8ef407b 100644 --- a/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainApplication.java +++ b/example/android/myapplication/src/main/java/com/wix/reactnativenotifications/app/MainApplication.java @@ -6,12 +6,18 @@ import com.facebook.react.ReactApplication; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; import com.facebook.react.shell.MainReactPackage; +import com.facebook.soloader.SoLoader; import com.wix.reactnativenotifications.RNNotificationsPackage; import java.util.Arrays; import java.util.List; public class MainApplication extends Application implements ReactApplication { + @Override + public void onCreate() { + super.onCreate(); + SoLoader.init(this, false); + } private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { @Override diff --git a/example/android/myapplication/src/main/res/layout/activity_main.xml b/example/android/myapplication/src/main/res/layout/activity_main.xml deleted file mode 100644 index 3f5177974ac954e0b6350b4bcdaffc4a45e5d62a..0000000000000000000000000000000000000000 --- a/example/android/myapplication/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - diff --git a/example/android/myapplication/src/main/res/layout/activity_main_prelollipop.xml b/example/android/myapplication/src/main/res/layout/activity_main_prelollipop.xml deleted file mode 100644 index 75a78a5f3d9a41811d010031a57be679f1603acf..0000000000000000000000000000000000000000 --- a/example/android/myapplication/src/main/res/layout/activity_main_prelollipop.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/lib/android/app/build.gradle b/lib/android/app/build.gradle index 4940660612897d897ea95a7fa808070e9d840ece..7e58848251b827dcfeb827635d15363b512b7dd0 100644 --- a/lib/android/app/build.gradle +++ b/lib/android/app/build.gradle @@ -16,6 +16,9 @@ android { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + debug { + debuggable true + } } testOptions { unitTests.all { t -> @@ -36,6 +39,16 @@ android { } } } + + flavorDimensions "RNNotifications.reactNativeVersion" + productFlavors { + reactNative59 { + dimension "RNNotifications.reactNativeVersion" + } + reactNative60 { + dimension "RNNotifications.reactNativeVersion" + } + } } dependencies { diff --git a/lib/android/app/src/main/java/com/wix/reactnativenotifications/RNNotificationsModule.java b/lib/android/app/src/main/java/com/wix/reactnativenotifications/RNNotificationsModule.java index c64c75e24a17eb8108ae0eebde7943baa0e3729c..9e235a3f53df492e99fb3225ec4be825fe6ba173 100644 --- a/lib/android/app/src/main/java/com/wix/reactnativenotifications/RNNotificationsModule.java +++ b/lib/android/app/src/main/java/com/wix/reactnativenotifications/RNNotificationsModule.java @@ -5,7 +5,6 @@ import android.app.Application; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.v4.app.NotificationManagerCompat; import android.util.Log; import com.facebook.react.bridge.ActivityEventListener; @@ -114,7 +113,7 @@ public class RNNotificationsModule extends ReactContextBaseJavaModule implements @ReactMethod public void isRegisteredForRemoteNotifications(Promise promise) { - boolean hasPermission = NotificationManagerCompat.from(getReactApplicationContext()).areNotificationsEnabled(); + boolean hasPermission = NotificationManagerCompatFacade.from(getReactApplicationContext()).areNotificationsEnabled(); promise.resolve(new Boolean(hasPermission)); } diff --git a/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/InitialNotificationHolder.java b/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/InitialNotificationHolder.java index 3636f41f7f3155d97870ab6113ab2b2b9f1bebd9..948d80edab9c5c6c511d783fa05a65ef6e0488d6 100644 --- a/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/InitialNotificationHolder.java +++ b/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/InitialNotificationHolder.java @@ -1,6 +1,5 @@ package com.wix.reactnativenotifications.core; -import android.support.annotation.Nullable; import com.wix.reactnativenotifications.core.notification.PushNotificationProps; @@ -32,7 +31,6 @@ public class InitialNotificationHolder { mNotification = null; } - @Nullable public PushNotificationProps get() { return mNotification; } diff --git a/package.json b/package.json index 20856259203962939a3e7b5d3a14ba1fb81df5c4..5d77e432db7134dce9505471f10b2b9cf2e3d2a2 100644 --- a/package.json +++ b/package.json @@ -28,13 +28,15 @@ "test": "node scripts/test", "start": "node ./scripts/start", "pretest-e2e-ios-release": "npm run build", + "clean": "node ./scripts/clean", "test-e2e-ios": "node ./scripts/test-e2e --ios", "test-e2e-ios-release": "node ./scripts/test-e2e --ios --release", "test-unit-ios": "node ./scripts/test-unit --ios", "test-unit-android": "node ./scripts/test-unit --android", "test-js": "node ./scripts/test-js", "xcode": "open example/ios/NotificationsExampleApp.xcodeproj", - "androidStudio": "open -a /Applications/Android\\ Studio.app ./example/android" + "androidStudio": "open -a /Applications/Android\\ Studio.app ./example/android", + "release": "node ./scripts/release" }, "nativePackage": true, "peerDependencies": { @@ -55,7 +57,7 @@ "ts-mockito": "^2.3.1", "mocha": "^2.5.3", "shell-utils": "1.x.x", - "react-native": "0.59.5", + "react-native": "0.60.5", "react": "16.8.6", "detox": "13.x.x", "jsc-android": "236355.x.x", diff --git a/scripts/clean.js b/scripts/clean.js new file mode 100644 index 0000000000000000000000000000000000000000..2a35e1121b37839258822c6e1bfaf2b919be16d5 --- /dev/null +++ b/scripts/clean.js @@ -0,0 +1,16 @@ +const exec = require('shell-utils').exec; + +run(); + +function run() { + exec.killPort(8081); + exec.execSync(`watchman watch-del-all || true`); + exec.execSync(`adb reverse tcp:8081 tcp:8081 || true`); + exec.execSync(`rm -rf lib/ios/DerivedData`); + exec.execSync(`rm -rf example/ios/DerivedData`); + exec.execSync(`rm -rf lib/android/build`); + exec.execSync(`rm -rf lib/android/app/build`); + exec.execSync(`rm -rf example/android/build`); + exec.execSync(`rm -rf example/android/app/build`); + exec.execSync(`rm -rf lib/dist`); +} diff --git a/scripts/release.js b/scripts/release.js new file mode 100644 index 0000000000000000000000000000000000000000..d04c6c2af35394a821c857cf642b59a8298e760e --- /dev/null +++ b/scripts/release.js @@ -0,0 +1,133 @@ +/* tslint:disable: no-console */ +const exec = require('shell-utils').exec; +const semver = require('semver'); +const fs = require('fs'); +const _ = require('lodash'); +const path = require('path'); + +// Workaround JS +const isRelease = process.env.RELEASE_BUILD === 'true'; + +const ONLY_ON_BRANCH = 'origin/master'; +const VERSION_TAG = isRelease ? 'latest' : 'snapshot'; +const VERSION_INC = 'patch'; + +function run() { + if (!validateEnv()) { + return; + } + setupGit(); + createNpmRc(); + versionTagAndPublish(); +} + +function validateEnv() { + if (!process.env.JENKINS_CI) { + throw new Error(`releasing is only available from CI`); + } + + if (!process.env.JENKINS_MASTER) { + console.log(`not publishing on a different build`); + return false; + } + + if (process.env.GIT_BRANCH !== ONLY_ON_BRANCH) { + console.log(`not publishing on branch ${process.env.GIT_BRANCH}`); + return false; + } + + return true; +} + +function setupGit() { + exec.execSyncSilent(`git config --global push.default simple`); + exec.execSyncSilent(`git config --global user.email "${process.env.GIT_EMAIL}"`); + exec.execSyncSilent(`git config --global user.name "${process.env.GIT_USER}"`); + const remoteUrl = new RegExp(`https?://(\\S+)`).exec(exec.execSyncRead(`git remote -v`))[1]; + exec.execSyncSilent(`git remote add deploy "https://${process.env.GIT_USER}:${process.env.GIT_TOKEN}@${remoteUrl}"`); + // exec.execSync(`git checkout ${ONLY_ON_BRANCH}`); +} + +function createNpmRc() { + exec.execSync(`rm -f package-lock.json`); + const content = ` +email=\${NPM_EMAIL} +//registry.npmjs.org/:_authToken=\${NPM_TOKEN} +`; + fs.writeFileSync(`.npmrc`, content); +} + +function versionTagAndPublish() { + const packageVersion = semver.clean(process.env.npm_package_version); + console.log(`package version: ${packageVersion}`); + + const currentPublished = findCurrentPublishedVersion(); + console.log(`current published version: ${currentPublished}`); + + const version = isRelease + ? process.env.VERSION + : semver.gt(packageVersion, currentPublished) + ? `${packageVersion}-snapshot.${process.env.BUILD_ID}` + : `${currentPublished}-snapshot.${process.env.BUILD_ID}`; + + console.log(`Publishing version: ${version}`); + + tryPublishAndTag(version); +} + +function findCurrentPublishedVersion() { + return exec.execSyncRead(`npm view ${process.env.npm_package_name} dist-tags.latest`); +} + +function tryPublishAndTag(version) { + let theCandidate = version; + for (let retry = 0; retry < 5; retry++) { + try { + tagAndPublish(theCandidate); + console.log(`Released ${theCandidate}`); + return; + } catch (err) { + const alreadyPublished = _.includes(err.toString(), 'You cannot publish over the previously published version'); + if (!alreadyPublished) { + throw err; + } + console.log(`previously published. retrying with increased ${VERSION_INC}...`); + theCandidate = semver.inc(theCandidate, VERSION_INC); + } + } +} + +function tagAndPublish(newVersion) { + console.log(`trying to publish ${newVersion}...`); + exec.execSync(`npm --no-git-tag-version version ${newVersion}`); + exec.execSync(`npm publish --tag ${VERSION_TAG}`); + exec.execSync(`git tag -a ${newVersion} -m "${newVersion}"`); + exec.execSyncSilent(`git push deploy ${newVersion} || true`); + if (isRelease) { + updatePackageJsonGit(newVersion); + } +} + +function getPackageJsonPath() { + return `${process.cwd()}/package.json`; +} + +function writePackageJson(packageJson) { + fs.writeFileSync(getPackageJsonPath(), JSON.stringify(packageJson, null, 2)); +} + +function readPackageJson() { + return JSON.parse(fs.readFileSync(getPackageJsonPath())); +} + +function updatePackageJsonGit(version) { + exec.execSync(`git checkout master`); + const packageJson = readPackageJson(); + packageJson.version = version; + writePackageJson(packageJson); + exec.execSync(`git add package.json`); + exec.execSync(`git commit -m"Update package.json version to ${version} [ci skip]"`); + exec.execSync(`git push deploy master`); +} + +run(); diff --git a/scripts/test-unit.js b/scripts/test-unit.js index fe103d3f6f9ed9c2ed4decc488c930f5f669a3f6..9ba2c40ea2cf50bd9dd05e55a35d621029789545 100644 --- a/scripts/test-unit.js +++ b/scripts/test-unit.js @@ -13,7 +13,7 @@ function run() { } function runAndroidUnitTests() { - const conf = release ? 'testReleaseUnitTest' : 'testDebugUnitTest'; + const conf = release ? 'testReactNative60ReleaseUnitTest' : 'testReactNative60DebugUnitTest'; if (android && process.env.JENKINS_CI) { const sdkmanager = '/usr/local/share/android-sdk/tools/bin/sdkmanager'; exec.execSync(`yes | ${sdkmanager} --licenses`);