Commit 9aa75961 authored by Amit Davidi's avatar Amit Davidi

Android example project

parent 8762d5e5
......@@ -2,9 +2,11 @@
Handle all the aspects of push notifications for your app, including remote and local notifications, interactive notifications, silent notifications, and more.
**All the native iOS notifications features are supported!** Android push support is in progress.
**All the native iOS notifications features are supported!**
### Supported Features (iOS)
## Supported Features
### iOS
- [Remote notifications](#handling-received-notifications).
- [Local notifications](#triggering-local-notifications).
......@@ -15,6 +17,9 @@ Handle all the aspects of push notifications for your app, including remote and
![Interactive notifications example](https://s3.amazonaws.com/nrjio/interactive.gif)
### <img src="https://cdn1.iconfinder.com/data/icons/ios-7-style-metro-ui-icons/512/MetroUI_OS_Android.png" width=25 height=25/> Android
TODO
## Installation
......@@ -58,13 +63,40 @@ And the following methods to support registration and receiving notifications:
}
```
### Android
WIP.
### <img src="https://cdn1.iconfinder.com/data/icons/ios-7-style-metro-ui-icons/512/MetroUI_OS_Android.png" width=25 height=25/> Android
> Note: Explicit installation on Android is only required if you're planning on **receiving push notifications**. It is **not** needed if you're only going to use 'local' notifications.
Push notifications on Android are managed and dispatched using [Google's GCM service](https://developers.google.com/cloud-messaging/gcm) (now integrated into Firebase). The following installation steps are a TL;DR of [Google's GCM setup guide](https://developers.google.com/cloud-messaging/android/client). You can follow them to get GCM integrated quickly, but we recommend you in the very least have a peek at the guide's overview.
#### Step #1: Subscribe to Google's GCM
To set GCM in your app, you must first create a Google Firebase API-project and obtain a **Sender ID** and a **Server API Key**. If you have no existing API projects yet, the easiest way to go about is to create a project and get these attributes using [this step-by-step installation process](https://developers.google.com/mobile/add); Use [this tutorial](https://code.tutsplus.com/tutorials/how-to-get-started-with-push-notifications-on-android--cms-25870) for insturctions.
Alternatively, follow [Google's complete guide](https://developers.google.com/cloud-messaging/android/client#create-an-api-project).
#### Step #2: Add Sender ID to Manifest File
```
<manifest>
...
<application>
...
// Replace '1234567890' with your sender ID.
// Important: Leave the trailing \0 intact!
<meta-data android:name="com.wix.reactnativenotifications.gcmSenderId" android:value="1234567890\0"/>
</application>
</manifest>
```
---
## Register to Push Notifications
### iOS
In order to handle notifications, you must register before- handle `remoteNotificationsRegistered` event.
In your React Native app:
......
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
import re
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#
lib_deps = []
for jarfile in glob(['libs/*.jar']):
name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile)
lib_deps.append(':' + name)
prebuilt_jar(
name = name,
binary_jar = jarfile,
)
for aarfile in glob(['libs/*.aar']):
name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile)
lib_deps.append(':' + name)
android_prebuilt_aar(
name = name,
aar = aarfile,
)
android_library(
name = 'all-libs',
exported_deps = lib_deps
)
android_library(
name = 'app-code',
srcs = glob([
'src/main/java/**/*.java',
]),
deps = [
':all-libs',
':build_config',
':res',
],
)
android_build_config(
name = 'build_config',
package = 'com.notificationsexampleapp',
)
android_resource(
name = 'res',
res = 'src/main/res',
package = 'com.notificationsexampleapp',
)
android_binary(
name = 'app',
package_type = 'debug',
manifest = 'src/main/AndroidManifest.xml',
keystore = '//android/keystores:debug',
deps = [
':app-code',
],
)
apply plugin: "com.android.application"
import com.android.build.OutputFile
/**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* and bundleReleaseJsAndAssets).
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation
* entryFile: "index.android.js",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // whether to bundle JS and assets in another build variant (if configured).
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
* // The configuration property can be in the following formats
* // 'bundleIn${productFlavor}${buildType}'
* // 'bundleIn${buildType}'
* // bundleInFreeDebug: true,
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for example, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"],
*
* // override which node gets called and with what additional arguments
* nodeExecutableAndArgs: ["node"]
*
* // supply additional arguments to the packager
* extraPackagerArgs: []
* ]
*/
apply from: "../../node_modules/react-native/react.gradle"
/**
* Set this to true to create two separate APKs instead of one:
* - An APK that only works on ARM devices
* - An APK that only works on x86 devices
* The advantage is the size of the APK is reduced by about 4MB.
* Upload all the APKs to the Play Store and people will download
* the correct one based on the CPU architecture of their device.
*/
def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
def enableProguardInReleaseBuilds = false
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.notificationsexampleapp"
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName "1.0"
ndk {
abiFilters "armeabi-v7a", "x86"
}
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86"
}
}
buildTypes {
release {
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
def versionCodes = ["armeabi-v7a":1, "x86":2]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
}
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:+" // From node_modules
}
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Disabling obfuscation is useful if you collect stack traces from production crashes
# (unless you are using a system that supports de-obfuscate the stack traces).
-dontobfuscate
# React Native
# Keep our interfaces so they can be used by other ProGuard rules.
# See http://sourceforge.net/p/proguard/bugs/466/
-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
# Do not strip any method/class that is annotated with @DoNotStrip
-keep @com.facebook.proguard.annotations.DoNotStrip class *
-keep @com.facebook.common.internal.DoNotStrip class *
-keepclassmembers class * {
@com.facebook.proguard.annotations.DoNotStrip *;
@com.facebook.common.internal.DoNotStrip *;
}
-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
void set*(***);
*** get*();
}
-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
-keep class * extends com.facebook.react.bridge.NativeModule { *; }
-keepclassmembers,includedescriptorclasses class * { native <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.UIProp <fields>; }
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }
-dontwarn com.facebook.react.**
# okhttp
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
# okio
-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn okio.**
import org.apache.tools.ant.taskdefs.condition.Os
def config = project.hasProperty("react") ? project.react : [];
def bundleAssetName = config.bundleAssetName ?: "index.android.bundle"
def entryFile = config.entryFile ?: "index.android.js"
// because elvis operator
def elvisFile(thing) {
return thing ? file(thing) : null;
}
def reactRoot = elvisFile(config.root) ?: file("../../")
def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"]
void runBefore(String dependentTaskName, Task task) {
Task dependentTask = tasks.findByPath(dependentTaskName);
if (dependentTask != null) {
dependentTask.dependsOn task
}
}
gradle.projectsEvaluated {
// Grab all build types and product flavors
def buildTypes = android.buildTypes.collect { type -> type.name }
def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
// When no product flavors defined, use empty
if (!productFlavors) productFlavors.add('')
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
// Create variant and target names
def targetName = "${productFlavorName.capitalize()}${buildTypeName.capitalize()}"
def targetPath = productFlavorName ?
"${productFlavorName}/${buildTypeName}" :
"${buildTypeName}"
// React js bundle directories
def jsBundleDirConfigName = "jsBundleDir${targetName}"
def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?:
file("$buildDir/intermediates/assets/${targetPath}")
def resourcesDirConfigName = "resourcesDir${targetName}"
def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?:
file("$buildDir/intermediates/res/merged/${targetPath}")
def jsBundleFile = file("$jsBundleDir/$bundleAssetName")
// Bundle task name for variant
def bundleJsAndAssetsTaskName = "bundle${targetName}JsAndAssets"
def currentBundleTask = tasks.create(
name: bundleJsAndAssetsTaskName,
type: Exec) {
group = "react"
description = "bundle JS and assets for ${targetName}."
// Create dirs if they are not there (e.g. the "clean" task just ran)
doFirst {
jsBundleDir.mkdirs()
resourcesDir.mkdirs()
}
// Set up inputs and outputs so gradle can cache the result
inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
outputs.dir jsBundleDir
outputs.dir resourcesDir
// Set up the call to the react-native cli
workingDir reactRoot
// Set up dev mode
def devEnabled = !targetName.toLowerCase().contains("release")
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}",
"--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
} else {
commandLine "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}",
"--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
}
enabled config."bundleIn${targetName}" ||
config."bundleIn${buildTypeName.capitalize()}" ?:
targetName.toLowerCase().contains("release")
}
// Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process
currentBundleTask.dependsOn("merge${targetName}Resources")
currentBundleTask.dependsOn("merge${targetName}Assets")
runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask)
runBefore("processX86${targetName}Resources", currentBundleTask)
runBefore("processUniversal${targetName}Resources", currentBundleTask)
runBefore("process${targetName}Resources", currentBundleTask)
}
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.smartnotificationsapp">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>
package com.notificationsexampleapp;
import com.facebook.react.ReactActivity;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "NotificationsExampleApp";
}
}
package com.notificationsexampleapp;
import android.app.Application;
import android.util.Log;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import java.util.Arrays;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage()
);
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
}
package com.smartnotificationsapp;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import java.util.Arrays;
import java.util.List;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "NotificationsExampleApp";
}
/**
* Returns whether dev mode should be enabled.
* This enables e.g. the dev menu.
*/
@Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
/**
* A list of packages used by the app. If the app uses additional views
* or modules besides the default ones, add more packages here.
*/
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage()
);
}
}
<resources>
<string name="app_name">NotificationsExampleApp</string>
</resources>
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
</style>
</resources>
......@@ -5,20 +5,21 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.android.tools.build:gradle:2.2.0'
}
}
allprojects {
repositories {
mavenLocal()
jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
......@@ -15,6 +15,4 @@
# 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
android.useDeprecatedNdk=true
# org.gradle.parallel=true
\ No newline at end of file
#Sun Oct 09 14:30:04 IDT 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
......@@ -42,11 +42,6 @@ case "`uname`" in
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
......@@ -61,9 +56,9 @@ while [ -h "$PRG" ] ; do
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
......@@ -114,6 +109,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
......
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "24.0.1"
defaultConfig {
applicationId "com.wix.reactnativenotifications"
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
ndk {
abiFilters "armeabi-v7a", "x86"
}
// packagingOptions {
// exclude "lib/arm64-v8a/librealm-jni.so"
// }
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
compile 'com.facebook.react:react-native:+'
compile project(':reactnativenotification')
testCompile 'junit:junit:4.12'
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/amitd/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wix.reactnativenotifications.app">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<meta-data android:name="com.wix.reactnativenotifications.gcmSenderId" android:value="434691868895\0"/>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
package com.wix.reactnativenotifications.app;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import com.facebook.react.LifecycleState;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;
import com.wix.reactnativenotifications.RNNotificationsPackage;
import static android.os.Build.VERSION.SDK_INT;
public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {
private static final int OVERLAY_PERMISSION_REQ_CODE = 1234;
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
.addPackage(new RNNotificationsPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
if (SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
} else {
startReactApplication();
}
}
@TargetApi(Build.VERSION_CODES.M)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
if (Settings.canDrawOverlays(this)) {
startReactApplication();
} else {
finish();
}
}
}
@Override
protected void onResume() {
super.onResume();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this, this);
}
}
@Override
protected void onPause() {
super.onPause();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause(this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostDestroy(this);
}
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
private void startReactApplication() {
mReactRootView.startReactApplication(mReactInstanceManager, "WixRNNotifications", null);
setContentView(mReactRootView);
}
}
<resources>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>
<resources>
<string name="app_name">Wix RN Notifications</string>
<string name="action_settings">Settings</string>
</resources>
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
</resources>
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "24.0.1"
defaultConfig {
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
// Google's GCM related framework components.
compile "com.google.android.gms:play-services-gcm:9+"
compile 'com.facebook.react:react-native:+'
testCompile 'junit:junit:4.12'
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/amitd/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wix.reactnativenotifications">
<!--
Permissions required for enabling GCM.
-->
<permission
android:name="${applicationId}.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<application>
<!--
Google's ready-to-use GcmReceiver.
1. Awaits actual GCM messages (e.g. push notifications) and invokes the GCM service with the concrete content.
2. Awaits instance-ID/token refresh requests from the GCM and invokes the Instance-ID listener service.
-->
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
<!-- Dispatched by the GcmReceiver when messages are received. -->
<service
android:name="com.wix.reactnativenotifications.GcmMessageHandlerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<!-- Dispatched by the GcmReceiver. Starts the designated refresh-handling service. -->
<service
android:name="com.wix.reactnativenotifications.GcmInstanceIdListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<service
android:name="com.wix.reactnativenotifications.GcmInstanceIdRefreshHandlerService"
android:exported="false" />
</application>
</manifest>
package com.wix.reactnativenotifications;
/*package*/ interface Defs {
String LOGTAG = "ReactNativeNotifs";
String GCM_SENDER_ID_ATTR_NAME = "com.wix.reactnativenotifications.gcmSenderId";
String TOKEN_RECEIVED_EVENT_NAME = "remoteNotificationsRegistered";
}
package com.wix.reactnativenotifications;
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);
}
}
package com.wix.reactnativenotifications;
import android.app.IntentService;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.util.Log;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import com.google.android.gms.iid.InstanceID;
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 GcmInstanceIdRefreshHandlerService extends IntentService {
public GcmInstanceIdRefreshHandlerService() {
super(GcmInstanceIdRefreshHandlerService.class.getSimpleName());
}
public GcmInstanceIdRefreshHandlerService(String name) {
super(name);
}
@Override
protected void onHandleIntent(Intent intent) {
final InstanceID instanceId = InstanceID.getInstance(getApplicationContext());
Log.d(LOGTAG, "GCM is refreshing token... instanceId=" + instanceId.getId());
// TODO why is this needed?
GoogleCloudMessaging.getInstance(getApplicationContext()).close();
final String registrationToken;
try {
registrationToken = instanceId.getToken(getSenderId(), GoogleCloudMessaging.INSTANCE_ID_SCOPE);
Log.i(LOGTAG, "GCM has a new token: instanceId=" + instanceId.getId() + ", token=" + registrationToken);
} catch (Exception e) {
Log.e(LOGTAG, "FATAL: Failed to fetch a fresh new token, instanceId=" + instanceId.getId(), e);
return;
}
notifyTokenEvent(registrationToken);
}
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 = getPackageManager().getApplicationInfo(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;
}
}
protected void notifyTokenEvent(String registrationToken) {
final ReactApplicationContext reactContext = RNNotificationsContextHolder.getReactContext();
// Note: Cannot assume react-context exists cause this is an async dispatched service.
if (reactContext != null) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(TOKEN_RECEIVED_EVENT_NAME, registrationToken);
}
}
}
package com.wix.reactnativenotifications;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.facebook.react.bridge.ReactApplicationContext;
import com.google.android.gms.gcm.GcmListenerService;
import static com.wix.reactnativenotifications.Defs.LOGTAG;
public class GcmMessageHandlerService extends GcmListenerService {
@Override
public void onMessageReceived(String s, Bundle bundle) {
Log.d(LOGTAG, "New message from GCM: " + bundle);
final Bundle notificationBundle = bundle.getBundle("notification");
final Bundle dataBundle = bundle.getBundle("data");
if (notificationBundle == null) {
return;
}
final String title = notificationBundle.getString("title");
final String body = notificationBundle.getString("body");
if (title == null || title.trim().isEmpty() || body == null || body.trim().isEmpty()) {
return;
}
final PendingIntent pendingIntent = getCTAPendingIntent(notificationBundle, dataBundle);
final Notification notification = buildNotification(title, body, pendingIntent);
postNotification((int) System.currentTimeMillis(), notification);
}
protected PendingIntent getCTAPendingIntent(Bundle notificationBundle, Bundle dataBundle) {
final Context appContext = getApplicationContext();
final Intent helperIntent = getPackageManager().getLaunchIntentForPackage(getPackageName());
final Intent intent;
try {
intent = new Intent(appContext, Class.forName(helperIntent.getComponent().getClassName()));
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("notification.meta", notificationBundle);
intent.putExtra("notification.data", dataBundle);
return PendingIntent.getActivity(appContext, 0, intent, 0);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
protected Notification buildNotification(String title, String body, PendingIntent intent) {
final Context appContext = getApplicationContext();
final Notification.Builder notificationBuilder = new Notification.Builder(appContext)
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(R.drawable.notification)
.setContentIntent(intent)
.setDefaults(Notification.DEFAULT_ALL)
.setAutoCancel(true);
final Notification notification = notificationBuilder.build();
return notification;
}
protected void postNotification(int id, Notification notification) {
final Context appContext = getApplicationContext();
final NotificationManager notificationManager = (NotificationManager) appContext.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(id, notification);
}
protected Activity getCurrentActivity() {
final ReactApplicationContext reactContext = RNNotificationsContextHolder.getReactContext();
if (reactContext == null) {
return null;
}
return reactContext.getCurrentActivity();
}
}
package com.wix.reactnativenotifications;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
public class RNNotificationsContextHolder extends ReactContextBaseJavaModule {
private static RNNotificationsContextHolder sInstance;
public static RNNotificationsContextHolder createInstance(ReactApplicationContext reactContext) {
if (sInstance == null) {
sInstance = new RNNotificationsContextHolder(reactContext);
}
return sInstance;
}
public static ReactApplicationContext getReactContext() {
return (sInstance == null ? null : sInstance.getReactApplicationContext());
}
private RNNotificationsContextHolder(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "RNNotificationsContextHolder";
}
}
package com.wix.reactnativenotifications;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import static com.wix.reactnativenotifications.Defs.LOGTAG;
public class RNNotificationsModule extends ReactContextBaseJavaModule implements ActivityEventListener {
public RNNotificationsModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "WixRNNotification";
}
@Override
public void initialize() {
Log.d(LOGTAG, "native module init");
final Context appContext = getReactApplicationContext().getApplicationContext();
final Intent tokenFetchIntent = new Intent(appContext, GcmInstanceIdRefreshHandlerService.class);
appContext.startService(tokenFetchIntent);
getReactApplicationContext().addActivityEventListener(this);
}
@Override
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
}
@Override
public void onNewIntent(Intent intent) {
Log.e(LOGTAG, "New intent: "+intent);
}
}
package com.wix.reactnativenotifications;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class RNNotificationsPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(
RNNotificationsContextHolder.createInstance(reactContext),
new RNNotificationsModule(reactContext));
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
<resources>
<string name="app_name">lib</string>
</resources>
from urllib2 import *
import urllib
import json
import sys
API_KEY = "AIzaSyBVtqdO_SgPVhhXnyNGC_VXSbIX-fxk1YY"
TOKEN = "eB6llQJLpw0:APA91bG3t07UNFyz_NPmGjgTZ8-tAUzwKmBJctKm2qpw973c-3vEINtTC3nVl89uJNv-l2LHzfd7fSmVPjeaVAQBE8tC9Pp2X5foteVMuBlHEiB5cznXqnP5RiCroGo1DdBIdWzBMwHW"
data={
"to": TOKEN,
"notification" : {
"body": "A very tiny one",
"title": "A tiny notification"
}
}
dataAsJSON = json.dumps(data)
request = Request(
"https://gcm-http.googleapis.com/gcm/send",
dataAsJSON,
{
"Authorization" : "key="+API_KEY,
"Content-type" : "application/json"
}
)
print urlopen(request).read()
rootProject.name = 'NotificationsExampleApp'
include ':app'
include ':reactnativenotification', ':myapplication'
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
'use strict';
import React, {Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import React, {Component} from 'react';
class NotificationsExampleApp extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native Notifications Demo App!
</Text>
<Text style={styles.instructions}>
To get started, edit index.android.js
</Text>
<Text style={styles.instructions}>
Shake or press menu button for dev menu
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
mainText: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('NotificationsExampleApp', () => NotificationsExampleApp);
class MainComponent extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.mainText}>Wix React Native Notifications</Text>
</View>
)
}
}
AppRegistry.registerComponent('WixRNNotifications', () => MainComponent);
......@@ -25,7 +25,8 @@
"uuid": "^2.0.3"
},
"peerDependencies": {
"react-native": ">=0.25.1"
"react-native": ">=0.25.1",
"react": "^0.14.5"
},
"devDependencies": {
"babel-eslint": "^6.0.2",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment