├── .gitignore ├── README.md ├── android ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── ioddly │ └── alarms │ ├── AlarmEmitter.java │ ├── AlarmHelper.java │ ├── AlarmModule.java │ ├── AlarmPackage.java │ ├── AlarmRun.java │ └── BootLauncher.java ├── index.android.js ├── index.d.ts └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # OSX 3 | # 4 | .DS_Store 5 | 6 | # node.js 7 | # 8 | node_modules/ 9 | npm-debug.log 10 | yarn-error.log 11 | 12 | 13 | # Xcode 14 | # 15 | build/ 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | xcuserdata 25 | *.xccheckout 26 | *.moved-aside 27 | DerivedData 28 | *.hmap 29 | *.ipa 30 | *.xcuserstate 31 | project.xcworkspace 32 | 33 | 34 | # Android/IntelliJ 35 | # 36 | build/ 37 | .idea 38 | .gradle 39 | local.properties 40 | *.iml 41 | 42 | # BUCK 43 | buck-out/ 44 | \.buckd/ 45 | *.keystore 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A react-native library for interacting with Android alarms. Requires RN 0.44 or greater. Includes TypeScript bindings. 2 | 3 | ## Warning 4 | 5 | This library is in hyper-alpha condition. Make sure to test that alarms fire properly in the desired manner before 6 | depending on them. APIs are subject to break, so pin by git commit. And you should probably use remote notifications 7 | anyway! 8 | 9 | ## Documentation 10 | 11 | Read up on the [Android Alarm](https://developer.android.com/training/scheduling/alarms.html) documentation, as 12 | everything applies to this library as well. 13 | 14 | Specifically: Many applications will be better served by using GCM, and all repeating alarms are inexact. 15 | 16 | ## Installation (ALARMS WILL FAIL SILENTLY IF YOU DON'T EDIT AndroidManifest.xml) 17 | 18 | In terminal 19 | 20 | ```shell 21 | yarn add git+https://github.com/ioddly/react-native-alarms.git 22 | react-native link 23 | ``` 24 | In your AndroidManifest.xml add this within within your `` tag (alarms will fail silently if you 25 | don't add this!) 26 | 27 | ```xml 28 | 29 | ``` 30 | 31 | Optional: If you want your application to start on boot and fire a special @boot event, so alarms can be restored, add 32 | this with your permissions: 33 | 34 | ```xml 35 | 36 | ``` 37 | 38 | And this within your `` 39 | 40 | ```xml 41 | 42 | 43 | 44 | 45 | 46 | 47 | ``` 48 | 49 | ## PendingIntents and Alarms 50 | 51 | react-native-alarm creates a PendingIntent for each named alarm. The name is used to check whether alarms already 52 | exist. It is your responsibility to manage alarms by name. If you re-use an alarm's name, it will be updated 53 | to the new parameters. 54 | 55 | ## Usage 56 | 57 | An Error will be thrown if arguments are provided with the incorrect type. 58 | 59 | Note that alarms can result in a new instance of react-native being instantiated if the device has gone idle; be aware 60 | of this if you're doing expensive things on startup. 61 | 62 | ### alarmSetElapsedRealtime(name: string, trigger: number, interval?: number) 63 | 64 | Creates an ELAPSED_REALTIME alarm. 65 | 66 | NAME is the name of the event that will be fired when the alarm goes off. 67 | 68 | TRIGGER is when the alarm will be triggered, in milliseconds. 69 | 70 | INTERVAL determines whether the alarm will be a repeating alarm, defaults to non-repeating. Can be either one of the 71 | provided interval constants, or a number in milliseconds above 60000 (alarms have a minimum interval of one minute, 72 | this is Android behavior). All repeating alarms are inexact. 73 | 74 | ### alarmSetElapsedRealtimeWakeup 75 | 76 | Same arguments as above, but creates an ELAPSED_REALTIME_WAKEUP alarm. 77 | 78 | ### alarmSetRTC(name: string, date: Date, interval?: number) 79 | ### alarmSetRTCWakeup(name: string, date: Date, interval?: number) 80 | 81 | Same as above, but results in an RTC alarm with the given Date object used to initialize a Java Calendar. 82 | 83 | ### alarmExists(name: string): Promise 84 | 85 | Returns a promise which will be called with an array containing a single boolean indicating whether a PendingIntent 86 | exists with the given name. 87 | 88 | Usage: 89 | ```js 90 | alarmExists('alarm1').then(([exists]) => console.log(`alarm1 ${exists ? 'exists' : 'does not exist'}`)); 91 | ``` 92 | 93 | ### setAlarm(name: string, type: number, opts: Object) 94 | 95 | This is the Java alarm-setting method. See the Java code for the fields of the OPTS object. You shouldn't have to use 96 | this. 97 | 98 | ### clearAlarm(name: string) 99 | 100 | Clears an alarm with the given name. Has no effect if called with an alarm that does not exist. 101 | 102 | ### launchMainActivity() 103 | 104 | A convenience method which can be used to launch the main activity when an alarm goes off. For e.g. an alarm clock 105 | application. May be irritating to users if an app launches when they do not expect it, use sparingly. 106 | 107 | ### AlarmEmitter 108 | 109 | AlarmEmitter is an instance of NativeEventEmitter used to listen specifically to alarm events. It has the same 110 | interface. 111 | 112 | #### AlarmEmitter.addListener(event, callback) 113 | 114 | Listen for an alarm (alarm fire events have the exact same name as alarms) or the @boot event. 115 | 116 | #### AlarmEmitter.removeAllListeners(event) 117 | 118 | Note this does not clear alarms on the Android side, but is recommended when an alarm is removed or no longer 119 | necessary. 120 | 121 | ### Constants 122 | 123 | #### `type` 124 | 125 | `RTC`, `RTC_WAKEUP`, `ELAPSED_REALTIME`, `ELAPSED_REALTIME_WAKEUP` 126 | 127 | #### `interval` 128 | 129 | `INTERVAL_FIFTEEN_MINUTES`, `INTERVAL_HALF_HOUR`, `INTERVAL_HOUR`, `INTERVAL_DAY`, `INTERVAL_HALF_DAY` 130 | 131 | Intervals may also be a number in milliseconds, minimum `60000`. 132 | 133 | ## Credits 134 | 135 | Some of the code in this library is derived from react-native-push-notifications and should be considered to be under 136 | the license of that library. 137 | 138 | ## Handy ADB commands 139 | 140 | Show alarms: `adb shell dumpsys alarm` 141 | 142 | Alarms should appear with your package name next to them. 143 | 144 | ## Manual linking 145 | 146 | 1. Open up `android/app/src/main/java/[...]/MainActivity.java` 147 | - Add `import com.ioddly.alarms.AlarmPackage;` to the imports at the top of the file 148 | - Add `new AlarmPackage()` to the list returned by the `getPackages()` method 149 | 2. Append the following lines to `android/settings.gradle`: 150 | ``` 151 | include ':react-native-alarms' 152 | project(':react-native-alarms').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-alarms/android') 153 | ``` 154 | 3. Insert the following lines inside the dependencies block in `android/app/build.gradle`: 155 | ``` 156 | compile project(':react-native-alarms') 157 | ``` 158 | 159 | 4. Edit AndroidManifest.xml as described above 160 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.1.3' 9 | } 10 | } 11 | 12 | 13 | apply plugin: 'com.android.library' 14 | 15 | android { 16 | compileSdkVersion 23 17 | buildToolsVersion "23.0.1" 18 | 19 | defaultConfig { 20 | minSdkVersion 16 21 | targetSdkVersion 22 22 | versionCode 1 23 | versionName "1.0" 24 | } 25 | lintOptions { 26 | abortOnError false 27 | } 28 | } 29 | 30 | repositories { 31 | mavenCentral() 32 | } 33 | 34 | dependencies { 35 | compile 'com.facebook.react:react-native:+' 36 | } 37 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/src/main/java/com/ioddly/alarms/AlarmEmitter.java: -------------------------------------------------------------------------------- 1 | package com.ioddly.alarms; 2 | 3 | import javax.annotation.Nullable; 4 | 5 | import com.facebook.react.bridge.*; 6 | 7 | public interface AlarmEmitter extends JavaScriptModule { 8 | void emit(String eventName, @Nullable Object data); 9 | } 10 | -------------------------------------------------------------------------------- /android/src/main/java/com/ioddly/alarms/AlarmHelper.java: -------------------------------------------------------------------------------- 1 | package com.ioddly.alarms; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.util.Log; 6 | 7 | /** Shared methods */ 8 | public class AlarmHelper { 9 | /** Find and launch the main activity of the application */ 10 | static void launchMainActivity(final Context context) { 11 | 12 | Class klass = null; 13 | try { 14 | Intent launch = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); 15 | klass = Class.forName(launch.getComponent().getClassName()); 16 | } catch(ClassNotFoundException e) { 17 | e.printStackTrace(); 18 | Log.e("RNAlarms", "failed to find main activity class"); 19 | return; 20 | } 21 | 22 | if(klass == null) { 23 | Log.e("RNAlarms", "failed to find main activity class"); 24 | } 25 | 26 | Log.e("RNAlarms", "starting activity " + klass.getCanonicalName()); 27 | Intent mainintent = new Intent(context, klass); 28 | mainintent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 29 | context.startActivity(mainintent); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /android/src/main/java/com/ioddly/alarms/AlarmModule.java: -------------------------------------------------------------------------------- 1 | package com.ioddly.alarms; 2 | 3 | import android.app.AlarmManager; 4 | import android.app.PendingIntent; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.net.Uri; 8 | import android.os.SystemClock; 9 | import android.util.Log; 10 | 11 | import com.facebook.react.bridge.Arguments; 12 | import com.facebook.react.bridge.Promise; 13 | import com.facebook.react.bridge.ReactApplicationContext; 14 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 15 | import com.facebook.react.bridge.ReactMethod; 16 | import com.facebook.react.bridge.ReadableMap; 17 | import com.facebook.react.bridge.WritableArray; 18 | import com.facebook.react.module.annotations.ReactModule; 19 | 20 | import java.util.Calendar; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | @ReactModule(name = "AlarmAndroid") 25 | public class AlarmModule extends ReactContextBaseJavaModule { 26 | public AlarmModule(ReactApplicationContext reactContext) { 27 | super(reactContext); 28 | Log.i("RNAlarms", "AlarmModule initialized"); 29 | } 30 | 31 | @Override 32 | public String getName() { 33 | return "AlarmAndroid"; 34 | } 35 | 36 | @Override 37 | /** 38 | * Return constants for use in JS code 39 | */ 40 | public Map getConstants() { 41 | final Map constants = new HashMap<>(); 42 | 43 | constants.put("RTC", AlarmManager.RTC); 44 | constants.put("RTC_WAKEUP", AlarmManager.RTC_WAKEUP); 45 | constants.put("ELAPSED_REALTIME", AlarmManager.ELAPSED_REALTIME); 46 | constants.put("ELAPSED_REALTIME_WAKEUP", AlarmManager.ELAPSED_REALTIME_WAKEUP); 47 | 48 | constants.put("INTERVAL_FIFTEEN_MINUTES", AlarmManager.INTERVAL_FIFTEEN_MINUTES); 49 | constants.put("INTERVAL_HALF_HOUR", AlarmManager.INTERVAL_HALF_HOUR); 50 | constants.put("INTERVAL_HOUR", AlarmManager.INTERVAL_HOUR); 51 | constants.put("INTERVAL_DAY", AlarmManager.INTERVAL_DAY); 52 | constants.put("INTERVAL_HALF_DAY", AlarmManager.INTERVAL_HALF_DAY); 53 | 54 | return constants; 55 | } 56 | 57 | /** 58 | * Creates a PendingIntent for an alarm 59 | * @param name Name of the alarm 60 | * @param flags PendingIntent flags 61 | * @return 62 | */ 63 | private PendingIntent createPending(final String name, final int flags) { 64 | Context context = getReactApplicationContext(); 65 | Intent intent = new Intent(context, AlarmRun.class); 66 | intent.putExtra("name", name); 67 | // This is so alarms may be cancelled 68 | intent.setAction(name); 69 | intent.setData(Uri.parse("http://"+name)); 70 | return PendingIntent.getBroadcast(context, 0, intent, flags); 71 | } 72 | 73 | /** 74 | * Check if an alarm exists 75 | * @param name Alarm name 76 | * @return true if alarm exists 77 | */ 78 | private boolean jAlarmExists(final String name) { 79 | return createPending(name, PendingIntent.FLAG_NO_CREATE) != null; 80 | } 81 | 82 | /** Clear an alarm by name */ 83 | private void jClearAlarm(final String name) { 84 | PendingIntent pending = createPending(name, PendingIntent.FLAG_NO_CREATE); 85 | if(pending != null) { 86 | pending.cancel(); 87 | ((AlarmManager) getReactApplicationContext().getSystemService(Context.ALARM_SERVICE)).cancel(pending); 88 | } else { 89 | Log.i("RNAlarms", "No PendingIntent found for alarm '"+name+"'"); 90 | } 91 | } 92 | 93 | @ReactMethod 94 | /** 95 | * React method: Check if an alarm exists. 96 | * @param name Alarm name 97 | * @param promise JS promise 98 | */ 99 | public void alarmExists(final String name, final Promise promise) { 100 | WritableArray args = Arguments.createArray(); 101 | args.pushBoolean(jAlarmExists(name)); 102 | promise.resolve(args); 103 | } 104 | 105 | /** 106 | * Set a new alarm 107 | * @param name Alarm name 108 | * @param type Android alarm type 109 | * @param opts Options 110 | */ 111 | @ReactMethod 112 | public void setAlarm(final String name, final int type, final ReadableMap opts) { 113 | boolean repeating = opts.hasKey("interval"); 114 | Context context = getReactApplicationContext(); 115 | 116 | AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 117 | 118 | long ms = 0; 119 | 120 | String wakeup = (type == AlarmManager.ELAPSED_REALTIME_WAKEUP || type == AlarmManager.RTC_WAKEUP) ? "_WAKEUP" : ""; 121 | String repeating_s = repeating ? " (repeating every "+opts.getInt("interval")+"ms) " : ""; 122 | 123 | if(type == AlarmManager.ELAPSED_REALTIME || type == AlarmManager.ELAPSED_REALTIME_WAKEUP) { 124 | ms = SystemClock.elapsedRealtime() + opts.getInt("trigger"); 125 | Log.i("RNAlarms", "ELAPSED_REALTIME"+ wakeup + " " + repeating_s + "ALARM '"+name+"' in " + opts.getInt("trigger") + "ms"); 126 | } else { 127 | Calendar calendar = Calendar.getInstance(); 128 | calendar.setTimeInMillis(System.currentTimeMillis()); 129 | if(opts.hasKey("date")) { 130 | calendar.set(Calendar.DATE, opts.getInt("date")); 131 | } 132 | if(opts.hasKey("hour")) { 133 | calendar.set(Calendar.HOUR_OF_DAY, opts.getInt("hour")); 134 | } 135 | if(opts.hasKey("minute")) { 136 | calendar.set(Calendar.MINUTE, opts.getInt("minute")); 137 | } 138 | if(opts.hasKey("second")) { 139 | calendar.set(Calendar.SECOND, opts.getInt("second")); 140 | } 141 | ms = calendar.getTimeInMillis(); 142 | Log.i("RNAlarms", "RTC" + wakeup + repeating_s + " " +name + " at date: " + calendar.get(Calendar.DATE) + " - h:m:s "+ calendar.get(Calendar.HOUR_OF_DAY) + ":" + calendar.get(Calendar.MINUTE) + ":" + calendar.get(Calendar.SECOND)); 143 | } 144 | 145 | PendingIntent pending; 146 | if(jAlarmExists(name)) { 147 | Log.i("RNAlarms", "PendingIntent already exists for alarm '"+name+"'; updating!"); 148 | jClearAlarm(name); 149 | pending = createPending(name, PendingIntent.FLAG_UPDATE_CURRENT); 150 | } else { 151 | pending = createPending(name, 0); 152 | } 153 | 154 | if(repeating) { 155 | int interval = opts.getInt("interval"); 156 | manager.setInexactRepeating(type, ms, interval, pending); 157 | } else { 158 | manager.set(type, ms, pending); 159 | } 160 | } 161 | 162 | /** Find and launch the main activity */ 163 | @ReactMethod 164 | public void launchMainActivity() { 165 | AlarmHelper.launchMainActivity(getReactApplicationContext()); 166 | } 167 | 168 | 169 | /** 170 | * Clear an existing alarm 171 | * @param name Alarm name 172 | */ 173 | @ReactMethod 174 | public void clearAlarm(String name) { 175 | Log.i("RNAlarms", "Clearing alarm '"+name+"'"); 176 | jClearAlarm(name); 177 | } 178 | } 179 | 180 | -------------------------------------------------------------------------------- /android/src/main/java/com/ioddly/alarms/AlarmPackage.java: -------------------------------------------------------------------------------- 1 | package com.ioddly.alarms; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.Collections; 12 | import java.util.List; 13 | 14 | public class AlarmPackage implements ReactPackage { 15 | @Override 16 | public List createViewManagers(ReactApplicationContext reactContext) { 17 | return Collections.emptyList(); 18 | } 19 | 20 | public List> createJSModules() { 21 | List> jsModules = new ArrayList>(Arrays.asList(AlarmEmitter.class)); 22 | return jsModules; 23 | } 24 | 25 | @Override 26 | public List createNativeModules( 27 | ReactApplicationContext reactContext) { 28 | List modules = new ArrayList<>(); 29 | 30 | modules.add(new AlarmModule(reactContext)); 31 | 32 | return modules; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /android/src/main/java/com/ioddly/alarms/AlarmRun.java: -------------------------------------------------------------------------------- 1 | package com.ioddly.alarms; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Handler; 7 | import android.os.Looper; 8 | import android.util.Log; 9 | 10 | import com.facebook.react.ReactApplication; 11 | import com.facebook.react.ReactInstanceManager; 12 | import com.facebook.react.bridge.ReactContext; 13 | 14 | public class AlarmRun extends BroadcastReceiver { 15 | /** 16 | * Fires alarm after ReactContext has been obtained 17 | * @param reactContext 18 | * @param alarmName 19 | */ 20 | public static void fire(ReactContext reactContext, String alarmName) { 21 | if(reactContext.hasActiveCatalystInstance()) { 22 | Log.i("RNAlarms", "Firing alarm '" + alarmName + "'"); 23 | reactContext.getJSModule(AlarmEmitter.class).emit(alarmName, null); 24 | } else { 25 | Log.i("RNAlarms", "no active catalyst instance; not firing alarm '" + alarmName + "'"); 26 | } 27 | } 28 | 29 | public void onReceive(final Context context, Intent intent) { 30 | Handler handler = new Handler(Looper.getMainLooper()); 31 | 32 | final String alarmName = intent.getStringExtra("name"); 33 | handler.post(new Runnable() { 34 | public void run() { 35 | ReactApplication reapp = ((ReactApplication) context.getApplicationContext()); 36 | ReactInstanceManager manager = reapp.getReactNativeHost().getReactInstanceManager(); 37 | ReactContext recontext = manager.getCurrentReactContext(); 38 | if(recontext != null) { 39 | Log.i("RNAlarms", "Attempting to fire alarm '" + alarmName + "'"); 40 | fire(recontext, alarmName); 41 | } else { 42 | Log.i("RNAlarms", "Application is closed; attempting to launch and fire alarm '" + alarmName + "'"); 43 | manager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { 44 | public void onReactContextInitialized(ReactContext context) { 45 | Log.i("RNAlarms", "Attempting to fire alarm '" + alarmName + "'"); 46 | fire(context, alarmName); 47 | } 48 | }); 49 | if(!manager.hasStartedCreatingInitialContext()) { 50 | manager.createReactContextInBackground(); 51 | } 52 | } 53 | } 54 | }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /android/src/main/java/com/ioddly/alarms/BootLauncher.java: -------------------------------------------------------------------------------- 1 | package com.ioddly.alarms; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.util.Log; 7 | 8 | import com.facebook.react.ReactApplication; 9 | import com.facebook.react.ReactInstanceManager; 10 | import com.facebook.react.bridge.ReactContext; 11 | 12 | /** 13 | * Boot launcher. Completely optional; starts the application on boot so that alarms can be restored. 14 | * May be irritating to users, use sparingly. 15 | */ 16 | public class BootLauncher extends BroadcastReceiver { 17 | @Override 18 | public void onReceive(final Context context, Intent intent) { 19 | if(!(intent.getAction().equals("android.intent.action.BOOT_COMPLETED"))) { 20 | return; 21 | } 22 | 23 | Log.i("RNAlarms", "received BOOT_COMPLETED event"); 24 | 25 | final String alarmName = "@boot"; 26 | ReactApplication reapp = ((ReactApplication) context.getApplicationContext()); 27 | ReactInstanceManager manager = reapp.getReactNativeHost().getReactInstanceManager(); 28 | ReactContext recontext = manager.getCurrentReactContext(); 29 | // Probably not necessary 30 | if(recontext != null) { 31 | Log.i("RNAlarms", "Attempting to fire boot event @boot"); 32 | AlarmRun.fire(recontext, alarmName); 33 | } else { 34 | Log.i("RNAlarms", "Application is closed; attempting to launch and fire boot event @boot'"); 35 | manager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { 36 | public void onReactContextInitialized(ReactContext context) { 37 | Log.i("RNAlarms", "Attempting to fire boot event @boot"); 38 | AlarmRun.fire(context, alarmName); 39 | } 40 | }); 41 | if (!manager.hasStartedCreatingInitialContext()) { 42 | manager.createReactContextInBackground(); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /index.android.js: -------------------------------------------------------------------------------- 1 | import {NativeEventEmitter, NativeModules} from 'react-native'; 2 | 3 | const BatchedBridge = require('react-native/Libraries/BatchedBridge/BatchedBridge'); 4 | const AlarmAndroid = NativeModules.AlarmAndroid; 5 | 6 | class _AlarmEmitter extends NativeEventEmitter {}; 7 | 8 | const AlarmEmitter = new _AlarmEmitter(); 9 | 10 | BatchedBridge.registerCallableModule('AlarmEmitter', AlarmEmitter); 11 | 12 | let {RTC, RTC_WAKEUP, ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, launchMainActivity, setAlarm, 13 | INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_DAY, INTERVAL_HALF_DAY} = AlarmAndroid; 14 | 15 | // Most of these wrappers are mainly to check arguments before calling Java code. This results in stack traces with JS 16 | // source information. 17 | 18 | // Sane wrappers around setAlarm, which takes a big and untyped bundle of opts for most arguments 19 | const alarmSetElapsedRealtime = (name, trigger, interval, wakeup) => { 20 | let prefix = `RNAlarms: alarmSetElapsedRealtime${wakeup ? 'Wakeup' : ''}: `; 21 | 22 | if(!(typeof name === 'string' || name instanceof String)) 23 | throw new Error(`${prefix} first argument name must be a string`); 24 | if(typeof trigger !== 'number') 25 | throw new Error(`${prefix} second argument date must be a Date`); 26 | if(interval && typeof interval !== 'number') 27 | throw new Error(`${prefix} third argument interval, if provided, must be a number`); 28 | 29 | let opts = { trigger: trigger }; 30 | if(interval) { 31 | opts.interval = interval; 32 | } 33 | 34 | return setAlarm(name, wakeup ? ELAPSED_REALTIME_WAKEUP : ELAPSED_REALTIME, opts); 35 | }; 36 | 37 | const alarmSetElapsedRealtimeWakeup = (name, trigger, interval) => { 38 | return alarmSetElapsedRealtime(name, trigger, interval, true); 39 | } 40 | 41 | const alarmSetRTC = (name, date, interval, wakeup) => { 42 | let prefix = `RNAlarms: alarmSetRTC${wakeup ? 'Wakeup' : ''}: `; 43 | 44 | // Check argument types 45 | if(!(typeof name === 'string' || name instanceof String)) 46 | throw new Error(`${prefix} first argument name must be a string`); 47 | if(!(date instanceof Date)) 48 | throw new Error(`${prefix} second argument date must be a Date`); 49 | if(interval && typeof interval != 'number') 50 | throw new Error(`${prefix} third argument interval, if provided, must be a number or one of the provided constants`); 51 | 52 | let opts = { date: date.getDate(), minute: date.getMinutes(), hour: date.getHours(), second: date.getSeconds() }; 53 | if(interval) { 54 | opts.interval = interval; 55 | } 56 | 57 | return setAlarm(name, wakeup ? RTC_WAKEUP : RTC, opts); 58 | }; 59 | 60 | const alarmSetRTCWakeup = (name, date, interval) => { 61 | return alarmSetRTC(name, date, interval, true); 62 | } 63 | 64 | const clearAlarm = (name) => { 65 | if(!(typeof name === 'string' || name instanceof String)) { 66 | throw new Error('RNAlarms: clearAlarm first argument must be a string'); 67 | } 68 | 69 | AlarmAndroid.clearAlarm(name); 70 | } 71 | 72 | const alarmExists = (name) => { 73 | if(!(typeof name === 'string' || name instanceof String)) { 74 | throw new Error('RNAlarms: alarmExists first argument must be a string'); 75 | } 76 | 77 | return AlarmAndroid.alarmExists(name); 78 | } 79 | 80 | export default {RTC, RTC_WAKEUP, ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, alarmExists, setAlarm, clearAlarm, 81 | AlarmEmitter, setAlarm, 82 | alarmSetElapsedRealtime, alarmSetElapsedRealtimeWakeup, alarmSetRTC, alarmSetRTCWakeup, 83 | INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_DAY, INTERVAL_HALF_DAY, launchMainActivity}; 84 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | interface rnAlarmEmitter { 2 | addListener(ev: string, callback: () => void); 3 | removeAllListeners(ev: string); 4 | } 5 | 6 | interface rnAlarmStatic { 7 | alarmSetElapsedRealtime(name: string, trigger: number, interval?: number); 8 | alarmSetElapsedRealtimeWakeup(name: string, trigger: number, interval?: number); 9 | alarmSetRTC(name: string, date: Date, interval?: number); 10 | alarmSetRTCWakeup(name: string, date: Date, interval?: number); 11 | alarmExists(name: string): Promise; 12 | 13 | launchMainActivity(); 14 | 15 | AlarmEmitter: rnAlarmEmitter; 16 | } 17 | 18 | declare var rnAlarmModule: rnAlarmStatic; 19 | 20 | declare module "react-native-alarms" { 21 | export default rnAlarmModule; 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "name": "react-native-alarms", 4 | "version": "0.0.1", 5 | "description": "", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "react-native" 11 | ], 12 | "author": "", 13 | "license": "MIT", 14 | "peerDependencies": { 15 | "react-native": ">=0.44" 16 | } 17 | } 18 | --------------------------------------------------------------------------------