├── index.d.ts ├── android ├── src │ └── main │ │ ├── assets │ │ ├── keys.mp3 │ │ └── popcorn.mp3 │ │ ├── java │ │ └── com │ │ │ └── liang │ │ │ ├── RNAlarmConstants.java │ │ │ ├── RNAlarmPackage.java │ │ │ ├── RNALarmCeiver.java │ │ │ └── RNAlarmModule.java │ │ └── AndroidManifest.xml └── build.gradle ├── index.js ├── ios ├── RNAlarm.xcworkspace │ └── contents.xcworkspacedata ├── RNAlarm.h ├── RNAlarm.podspec ├── RNAlarm.xcodeproj │ └── project.pbxproj └── RNAlarm.m ├── package.json ├── LICENSE └── README.md /index.d.ts: -------------------------------------------------------------------------------- 1 | import { NativeModulesStatic } from 'react-native'; 2 | 3 | export declare const { RNAlarm } : NativeModulesStatic; -------------------------------------------------------------------------------- /android/src/main/assets/keys.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartliang/react-native-alarm/HEAD/android/src/main/assets/keys.mp3 -------------------------------------------------------------------------------- /android/src/main/assets/popcorn.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartliang/react-native-alarm/HEAD/android/src/main/assets/popcorn.mp3 -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | import { NativeModules } from 'react-native'; 3 | 4 | const { RNAlarm } = NativeModules; 5 | 6 | export default RNAlarm; 7 | -------------------------------------------------------------------------------- /ios/RNAlarm.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | 3 | 5 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/RNAlarm.h: -------------------------------------------------------------------------------- 1 | 2 | #if __has_include("RCTBridgeModule.h") 3 | #import "RCTBridgeModule.h" 4 | #else 5 | #import 6 | #endif 7 | @import UserNotifications; 8 | @import UIKit; 9 | 10 | @interface RNAlarm : NSObject 11 | //-(void)playSound(); 12 | @end 13 | 14 | -------------------------------------------------------------------------------- /android/src/main/java/com/liang/RNAlarmConstants.java: -------------------------------------------------------------------------------- 1 | package com.liang; 2 | 3 | /** 4 | * Created by GBLiang on 9/22/2017. 5 | */ 6 | 7 | public class RNAlarmConstants { 8 | public final static String REACT_NATIVE_ALARM = "REACT_NATIVE_ALARM"; 9 | public final static String REACT_NATIVE_ALARM_TITLE = "title"; 10 | public final static String REACT_NATIVE_ALARM_MUSIC_URI = "musicUri"; 11 | } 12 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-alarm", 3 | "version": "1.2.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "react-native" 11 | ], 12 | "author": "gbliang@outlook.com", 13 | "license": "MIT", 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/smartliang/react-native-alarm.git" 17 | }, 18 | "peerDependencies": { 19 | "react-native": "^0.47.0" 20 | }, 21 | "types": "index.d.ts" 22 | } 23 | -------------------------------------------------------------------------------- /ios/RNAlarm.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | s.name = "RNAlarm" 4 | s.version = "1.0.0" 5 | s.summary = "RNAlarm" 6 | s.description = <<-DESC 7 | RNAlarm 8 | DESC 9 | s.homepage = "" 10 | s.license = "MIT" 11 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" } 12 | s.author = { "author" => "author@domain.cn" } 13 | s.platform = :ios, "7.0" 14 | s.source = { :git => "https://github.com/author/RNAlarm.git", :tag => "master" } 15 | s.source_files = "RNAlarm/**/*.{h,m}" 16 | s.requires_arc = true 17 | 18 | 19 | s.dependency "React" 20 | #s.dependency "others" 21 | 22 | end 23 | 24 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | } 10 | } 11 | 12 | apply plugin: 'com.android.library' 13 | 14 | android { 15 | compileSdkVersion 23 16 | buildToolsVersion "25.0.0" 17 | 18 | defaultConfig { 19 | minSdkVersion 16 20 | targetSdkVersion 22 21 | versionCode 1 22 | versionName "1.0" 23 | } 24 | lintOptions { 25 | abortOnError false 26 | } 27 | } 28 | 29 | repositories { 30 | mavenCentral() 31 | } 32 | 33 | dependencies { 34 | compile 'com.facebook.react:react-native:+' 35 | } 36 | -------------------------------------------------------------------------------- /android/src/main/java/com/liang/RNAlarmPackage.java: -------------------------------------------------------------------------------- 1 | 2 | package com.liang; 3 | 4 | import java.util.Arrays; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.bridge.NativeModule; 10 | import com.facebook.react.bridge.ReactApplicationContext; 11 | import com.facebook.react.uimanager.ViewManager; 12 | import com.facebook.react.bridge.JavaScriptModule; 13 | public class RNAlarmPackage implements ReactPackage { 14 | @Override 15 | public List createNativeModules(ReactApplicationContext reactContext) { 16 | return Arrays.asList(new RNAlarmModule(reactContext)); 17 | } 18 | 19 | // Deprecated from RN 0.47 20 | public List> createJSModules() { 21 | return Collections.emptyList(); 22 | } 23 | 24 | @Override 25 | public List createViewManagers(ReactApplicationContext reactContext) { 26 | return Collections.emptyList(); 27 | } 28 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 liang guo bin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # react-native-alarm 3 | 4 | ## Getting started 5 | 6 | `$ npm install react-native-alarm --save` 7 | 8 | ### Mostly automatic installation 9 | 10 | `$ react-native link react-native-alarm` 11 | 12 | ### Manual installation 13 | 14 | 15 | #### iOS 16 | 17 | 1. In XCode, in the project navigator, right click `Libraries` ➜ `Add Files to [your project's name]` 18 | 2. Go to `node_modules` ➜ `react-native-alarm` and add `RNAlarm.xcodeproj` 19 | 3. In XCode, in the project navigator, select your project. Add `libRNAlarm.a` to your project's `Build Phases` ➜ `Link Binary With Libraries` 20 | 4. Run your project (`Cmd+R`)< 21 | 22 | #### Android 23 | 24 | 1. Open up `android/app/src/main/java/[...]/MainActivity.java` 25 | - Add `import com.liang.RNAlarmPackage;` to the imports at the top of the file 26 | - Add `new RNAlarmPackage()` to the list returned by the `getPackages()` method 27 | 2. Append the following lines to `android/settings.gradle`: 28 | ``` 29 | include ':react-native-alarm' 30 | project(':react-native-alarm').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-alarm/android') 31 | ``` 32 | 3. Insert the following lines inside the dependencies block in `android/app/build.gradle`: 33 | ``` 34 | compile project(':react-native-alarm') 35 | ``` 36 | 37 | 38 | ## Usage 39 | ```javascript 40 | import RNAlarm from 'react-native-alarm'; 41 | 42 | // TODO: What to do with the module? 43 | RNAlarm.setAlarm('Meeting', 44 | 'Meeting with customer', 45 | '', 46 | '', 47 | () => { 48 | // Success callback function 49 | }, 50 | () => { 51 | // Fail callback function 52 | }); 53 | ``` 54 | 55 | -------------------------------------------------------------------------------- /android/src/main/java/com/liang/RNALarmCeiver.java: -------------------------------------------------------------------------------- 1 | package com.liang; 2 | 3 | import android.app.AlertDialog; 4 | import android.app.Notification; 5 | import android.app.NotificationManager; 6 | import android.app.PendingIntent; 7 | import android.content.BroadcastReceiver; 8 | import android.content.Context; 9 | import android.content.DialogInterface; 10 | import android.content.Intent; 11 | import android.graphics.drawable.Drawable; 12 | import android.media.MediaPlayer; 13 | import android.media.RingtoneManager; 14 | import android.net.Uri; 15 | import android.os.CountDownTimer; 16 | import android.os.Vibrator; 17 | import android.view.WindowManager; 18 | import android.widget.Toast; 19 | 20 | import com.facebook.common.util.UriUtil; 21 | 22 | import java.io.IOException; 23 | 24 | import static android.content.Context.NOTIFICATION_SERVICE; 25 | 26 | /** 27 | * Created by GBLiang on 9/22/2017. 28 | */ 29 | 30 | public class RNALarmCeiver extends BroadcastReceiver { 31 | 32 | static MediaPlayer player = new MediaPlayer(); 33 | 34 | 35 | 36 | @Override 37 | public void onReceive(Context context, Intent intent) { 38 | 39 | if(intent.getExtras().getBoolean("stopNotification")) { 40 | if (player.isPlaying()) { 41 | player.stop(); 42 | player.reset(); 43 | } 44 | } 45 | else { 46 | 47 | Uri uri; 48 | String title = intent.getStringExtra(RNAlarmConstants.REACT_NATIVE_ALARM_TITLE); 49 | String musicUri = intent.getStringExtra(RNAlarmConstants.REACT_NATIVE_ALARM_MUSIC_URI); 50 | if (musicUri == null || "".equals(musicUri)) { 51 | uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); 52 | } else { 53 | uri = UriUtil.parseUriOrNull(musicUri); 54 | } 55 | 56 | 57 | //Toast.makeText(context,title,Toast.LENGTH_SHORT).show(); 58 | 59 | // AlertDialog.Builder normalDialog = 60 | // new AlertDialog.Builder(context); 61 | // normalDialog.setTitle(title); 62 | // normalDialog.setNegativeButton("关闭", 63 | // new DialogInterface.OnClickListener() { 64 | // @Override 65 | // public void onClick(DialogInterface dialog, int which) { 66 | // dialog.dismiss(); 67 | // player.stop(); 68 | // } 69 | // }); 70 | // 71 | // AlertDialog dialog = normalDialog.create(); 72 | // dialog.getWindow() 73 | // .setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 74 | // dialog.show(); 75 | 76 | PendingIntent pi = PendingIntent.getActivity(context, 100, intent, PendingIntent.FLAG_CANCEL_CURRENT); 77 | 78 | Notification.Builder notificationBuilder = new Notification.Builder(context) 79 | .setSmallIcon(android.R.drawable.sym_def_app_icon)//设置小图标 80 | .setVibrate(new long[]{0,6000}) 81 | .setContentTitle(title) 82 | .setContentText("闹钟"); 83 | 84 | 85 | Notification notification = notificationBuilder.build(); 86 | notificationBuilder.setDefaults(Notification.DEFAULT_ALL); 87 | notificationBuilder.setFullScreenIntent(pi, true); 88 | notificationBuilder.setDeleteIntent(createOnDismissedIntent(context)); 89 | notificationBuilder.setAutoCancel(true); 90 | NotificationManager notificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); 91 | notificationManager.notify(0, notification); 92 | 93 | 94 | try { 95 | player.setDataSource(context, uri); 96 | player.setLooping(true); 97 | player.prepareAsync(); 98 | player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 99 | @Override 100 | public void onPrepared(MediaPlayer mp) { 101 | player.start(); 102 | new CountDownTimer(50000, 10000) { 103 | public void onTick(long millisUntilFinished) { 104 | 105 | } 106 | 107 | public void onFinish() { 108 | if (player.isPlaying()) { 109 | player.stop(); 110 | player.reset(); 111 | } 112 | } 113 | }.start(); 114 | } 115 | }); 116 | 117 | } catch (IOException e) { 118 | uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); 119 | //e.printStackTrace(); 120 | } 121 | 122 | if (musicUri != null && !"".equals(musicUri)) { 123 | try { 124 | 125 | player.setDataSource(context, uri); 126 | player.setLooping(true); 127 | player.prepareAsync(); 128 | player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 129 | @Override 130 | public void onPrepared(MediaPlayer mp) { 131 | player.start(); 132 | new CountDownTimer(50000, 10000) { 133 | public void onTick(long millisUntilFinished) { 134 | 135 | } 136 | 137 | public void onFinish() { 138 | if (player.isPlaying()) { 139 | player.stop(); 140 | player.reset(); 141 | } 142 | } 143 | }.start(); 144 | } 145 | }); 146 | } catch (IOException e) { 147 | e.printStackTrace(); 148 | } 149 | } 150 | } 151 | } 152 | 153 | private PendingIntent createOnDismissedIntent(Context context) { 154 | Intent intent = new Intent(RNAlarmConstants.REACT_NATIVE_ALARM); 155 | intent.putExtra("stopNotification", true); 156 | PendingIntent pendingIntent = 157 | PendingIntent.getBroadcast(context,1, intent, 0); 158 | return pendingIntent; 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /android/src/main/java/com/liang/RNAlarmModule.java: -------------------------------------------------------------------------------- 1 | 2 | package com.liang; 3 | 4 | import android.app.AlarmManager; 5 | import android.app.PendingIntent; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.content.SharedPreferences; 9 | import android.content.res.AssetFileDescriptor; 10 | import android.media.MediaPlayer; 11 | import android.support.annotation.Nullable; 12 | import android.support.v4.content.WakefulBroadcastReceiver; 13 | import android.text.format.DateFormat; 14 | import android.util.Log; 15 | import android.util.TimeUtils; 16 | 17 | import com.facebook.react.bridge.Promise; 18 | import com.facebook.react.bridge.ReactApplicationContext; 19 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 20 | import com.facebook.react.bridge.ReactMethod; 21 | import com.facebook.react.bridge.Callback; 22 | import com.facebook.react.uimanager.IllegalViewOperationException; 23 | 24 | import java.io.Console; 25 | import java.text.SimpleDateFormat; 26 | import java.util.Calendar; 27 | import java.util.Date; 28 | 29 | import static android.R.attr.track; 30 | import static android.R.attr.type; 31 | 32 | public class RNAlarmModule extends ReactContextBaseJavaModule { 33 | 34 | private final ReactApplicationContext reactContext; 35 | private SharedPreferences sharedPreferences; 36 | 37 | public RNAlarmModule(ReactApplicationContext reactContext) { 38 | super(reactContext); 39 | this.reactContext = reactContext; 40 | this.sharedPreferences = reactContext.getSharedPreferences(getName(),Context.MODE_PRIVATE); 41 | } 42 | 43 | @Override 44 | public String getName() { 45 | return "RNAlarm"; 46 | } 47 | 48 | public Boolean getAlarmStatus(String triggerTime){ 49 | String value = sharedPreferences.getString(triggerTime, null); 50 | if (value == null) 51 | return null; 52 | else { 53 | return value == "error" ? false : true; 54 | } 55 | } 56 | 57 | public void setAlarm1(String triggerTime, String value){ 58 | SharedPreferences.Editor editor = sharedPreferences.edit(); 59 | editor.putString(triggerTime,value); 60 | editor.commit(); 61 | } 62 | 63 | @ReactMethod 64 | public void playTipSound(String fileName){ 65 | MediaPlayer mp = new MediaPlayer(); 66 | try { 67 | if (mp.isPlaying()) { 68 | mp.stop(); 69 | } 70 | if(mp!=null){ 71 | mp.release(); 72 | mp = new MediaPlayer(); 73 | } 74 | AssetFileDescriptor descriptor = reactContext.getResources().getAssets().openFd(fileName + ".mp3"); 75 | mp.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), 76 | descriptor.getLength()); 77 | mp.prepare(); 78 | mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 79 | @Override 80 | public void onPrepared(MediaPlayer mp) { 81 | mp.setLooping(false); 82 | mp.start(); 83 | } 84 | }); 85 | }catch(Exception ex){ 86 | ex.printStackTrace(); 87 | } 88 | 89 | } 90 | 91 | @ReactMethod 92 | public void initAlarm(@Nullable Callback successCallback){ 93 | if(successCallback != null) { 94 | successCallback.invoke(true); 95 | } 96 | } 97 | 98 | @ReactMethod 99 | public void clearAlarm(){ 100 | SharedPreferences sharedPreferences = reactContext.getSharedPreferences(getName(),Context.MODE_PRIVATE); 101 | SharedPreferences.Editor editor = sharedPreferences.edit(); 102 | editor.clear(); 103 | } 104 | 105 | @ReactMethod 106 | public void setAlarm(String triggerTime, String title, @Nullable String isRetry, @Nullable String musicUri, @Nullable Callback successCallback, @Nullable Callback errorCallback) { 107 | try { 108 | Boolean alarmStatus = getAlarmStatus(triggerTime); 109 | if(isRetry != null && !isRetry.isEmpty()) 110 | setAlarm1(triggerTime,null); 111 | 112 | if (alarmStatus != null) 113 | { 114 | if (alarmStatus) { 115 | successCallback.invoke(); 116 | return; 117 | }else { 118 | errorCallback.invoke(); 119 | return; 120 | } 121 | } 122 | 123 | AlarmManager alarmManager = (AlarmManager) reactContext.getSystemService(Context.ALARM_SERVICE); 124 | Intent intent = new Intent(RNAlarmConstants.REACT_NATIVE_ALARM); 125 | intent.putExtra(RNAlarmConstants.REACT_NATIVE_ALARM_TITLE,title); 126 | intent.putExtra(RNAlarmConstants.REACT_NATIVE_ALARM_MUSIC_URI, musicUri); 127 | PendingIntent pendingIntent = PendingIntent.getBroadcast(reactContext, type, intent, PendingIntent.FLAG_UPDATE_CURRENT); 128 | 129 | SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss"); 130 | 131 | long triggerTimeMillis = Long.parseLong(triggerTime); 132 | Calendar originalTimeCal = Calendar.getInstance(); 133 | originalTimeCal.setTimeInMillis(triggerTimeMillis); 134 | Log.w("originalTimeCal",formatter.format(originalTimeCal.getTime())); 135 | 136 | Calendar currentTimeCal = Calendar.getInstance(); 137 | currentTimeCal.setTime(new Date()); 138 | Log.w("currentTimeCal",formatter.format(currentTimeCal.getTime())); 139 | 140 | //compare alarm and currentTime 141 | if (triggerTimeMillis - currentTimeCal.getTimeInMillis() > 0) 142 | { 143 | Calendar calendar = Calendar.getInstance(); 144 | calendar.setTimeInMillis(triggerTimeMillis); 145 | formatter.format(calendar.getTime()); 146 | 147 | 148 | alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTimeMillis, pendingIntent); 149 | setAlarm1(triggerTime,triggerTime); 150 | 151 | successCallback.invoke(); 152 | return; 153 | 154 | }else { 155 | setAlarm1(triggerTime, "error"); 156 | if (errorCallback != null) { 157 | // -1 闹钟时间设置不能在当前时间之前 158 | errorCallback.invoke("-1"); 159 | return; 160 | } 161 | } 162 | 163 | } catch (IllegalViewOperationException e) { 164 | if(errorCallback == null ){ 165 | System.out.print(e.toString()); 166 | }else{ 167 | setAlarm1(triggerTime,"error"); 168 | errorCallback.invoke(e.getMessage()); 169 | } 170 | } catch (NumberFormatException e) { 171 | if(errorCallback == null ){ 172 | System.out.print(e.toString()); 173 | }else{ 174 | setAlarm1(triggerTime,"error"); 175 | errorCallback.invoke(e.getMessage()); 176 | } 177 | } 178 | } 179 | 180 | // @ReactMethod 181 | // public void setAlarm(String triggerTime, String title, @Nullable String musicUri, Promise promise) { 182 | // try { 183 | // AlarmManager alarmManager = (AlarmManager) reactContext.getSystemService(Context.ALARM_SERVICE); 184 | // Intent intent = new Intent(RNAlarmConstants.REACT_NATIVE_ALARM); 185 | // intent.putExtra(RNAlarmConstants.REACT_NATIVE_ALARM_TITLE,title); 186 | // intent.putExtra(RNAlarmConstants.REACT_NATIVE_ALARM_MUSIC_URI, musicUri); 187 | // PendingIntent pendingIntent = PendingIntent.getBroadcast(reactContext, type, intent, PendingIntent.FLAG_UPDATE_CURRENT); 188 | // 189 | // long startTime = Long.parseLong(triggerTime); 190 | // alarmManager.setExact(AlarmManager.RTC_WAKEUP, startTime, pendingIntent); 191 | // promise.resolve(0); 192 | // } catch (IllegalViewOperationException e) { 193 | // promise.reject(e); 194 | // } catch (NumberFormatException e) { 195 | // promise.reject(e); 196 | // } 197 | // } 198 | } -------------------------------------------------------------------------------- /ios/RNAlarm.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B3E7B58A1CC2AC0600A0062D /* RNAlarm.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNAlarm.m */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | 58B511D91A9E6C8500147676 /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = "include/$(PRODUCT_NAME)"; 18 | dstSubfolderSpec = 16; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 0; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 134814201AA4EA6300B7C361 /* libRNAlarm.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNAlarm.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | B3E7B5881CC2AC0600A0062D /* RNAlarm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNAlarm.h; sourceTree = ""; }; 28 | B3E7B5891CC2AC0600A0062D /* RNAlarm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNAlarm.m; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 58B511D81A9E6C8500147676 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 134814211AA4EA7D00B7C361 /* Products */ = { 43 | isa = PBXGroup; 44 | children = ( 45 | 134814201AA4EA6300B7C361 /* libRNAlarm.a */, 46 | ); 47 | name = Products; 48 | sourceTree = ""; 49 | }; 50 | 58B511D21A9E6C8500147676 = { 51 | isa = PBXGroup; 52 | children = ( 53 | B3E7B5881CC2AC0600A0062D /* RNAlarm.h */, 54 | B3E7B5891CC2AC0600A0062D /* RNAlarm.m */, 55 | 134814211AA4EA7D00B7C361 /* Products */, 56 | ); 57 | sourceTree = ""; 58 | }; 59 | /* End PBXGroup section */ 60 | 61 | /* Begin PBXNativeTarget section */ 62 | 58B511DA1A9E6C8500147676 /* RNAlarm */ = { 63 | isa = PBXNativeTarget; 64 | buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNAlarm" */; 65 | buildPhases = ( 66 | 58B511D71A9E6C8500147676 /* Sources */, 67 | 58B511D81A9E6C8500147676 /* Frameworks */, 68 | 58B511D91A9E6C8500147676 /* CopyFiles */, 69 | ); 70 | buildRules = ( 71 | ); 72 | dependencies = ( 73 | ); 74 | name = RNAlarm; 75 | productName = RCTDataManager; 76 | productReference = 134814201AA4EA6300B7C361 /* libRNAlarm.a */; 77 | productType = "com.apple.product-type.library.static"; 78 | }; 79 | /* End PBXNativeTarget section */ 80 | 81 | /* Begin PBXProject section */ 82 | 58B511D31A9E6C8500147676 /* Project object */ = { 83 | isa = PBXProject; 84 | attributes = { 85 | LastUpgradeCheck = 0830; 86 | ORGANIZATIONNAME = Facebook; 87 | TargetAttributes = { 88 | 58B511DA1A9E6C8500147676 = { 89 | CreatedOnToolsVersion = 6.1.1; 90 | }; 91 | }; 92 | }; 93 | buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNAlarm" */; 94 | compatibilityVersion = "Xcode 3.2"; 95 | developmentRegion = English; 96 | hasScannedForEncodings = 0; 97 | knownRegions = ( 98 | en, 99 | ); 100 | mainGroup = 58B511D21A9E6C8500147676; 101 | productRefGroup = 58B511D21A9E6C8500147676; 102 | projectDirPath = ""; 103 | projectRoot = ""; 104 | targets = ( 105 | 58B511DA1A9E6C8500147676 /* RNAlarm */, 106 | ); 107 | }; 108 | /* End PBXProject section */ 109 | 110 | /* Begin PBXSourcesBuildPhase section */ 111 | 58B511D71A9E6C8500147676 /* Sources */ = { 112 | isa = PBXSourcesBuildPhase; 113 | buildActionMask = 2147483647; 114 | files = ( 115 | B3E7B58A1CC2AC0600A0062D /* RNAlarm.m in Sources */, 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | /* End PBXSourcesBuildPhase section */ 120 | 121 | /* Begin XCBuildConfiguration section */ 122 | 58B511ED1A9E6C8500147676 /* Debug */ = { 123 | isa = XCBuildConfiguration; 124 | buildSettings = { 125 | ALWAYS_SEARCH_USER_PATHS = NO; 126 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 127 | CLANG_CXX_LIBRARY = "libc++"; 128 | CLANG_ENABLE_MODULES = YES; 129 | CLANG_ENABLE_OBJC_ARC = YES; 130 | CLANG_WARN_BOOL_CONVERSION = YES; 131 | CLANG_WARN_CONSTANT_CONVERSION = YES; 132 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 133 | CLANG_WARN_EMPTY_BODY = YES; 134 | CLANG_WARN_ENUM_CONVERSION = YES; 135 | CLANG_WARN_INFINITE_RECURSION = YES; 136 | CLANG_WARN_INT_CONVERSION = YES; 137 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 138 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 139 | CLANG_WARN_UNREACHABLE_CODE = YES; 140 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 141 | COPY_PHASE_STRIP = NO; 142 | ENABLE_STRICT_OBJC_MSGSEND = YES; 143 | ENABLE_TESTABILITY = YES; 144 | GCC_C_LANGUAGE_STANDARD = gnu99; 145 | GCC_DYNAMIC_NO_PIC = NO; 146 | GCC_NO_COMMON_BLOCKS = YES; 147 | GCC_OPTIMIZATION_LEVEL = 0; 148 | GCC_PREPROCESSOR_DEFINITIONS = ( 149 | "DEBUG=1", 150 | "$(inherited)", 151 | ); 152 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 153 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 154 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 155 | GCC_WARN_UNDECLARED_SELECTOR = YES; 156 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 157 | GCC_WARN_UNUSED_FUNCTION = YES; 158 | GCC_WARN_UNUSED_VARIABLE = YES; 159 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 160 | MTL_ENABLE_DEBUG_INFO = YES; 161 | ONLY_ACTIVE_ARCH = YES; 162 | SDKROOT = iphoneos; 163 | }; 164 | name = Debug; 165 | }; 166 | 58B511EE1A9E6C8500147676 /* Release */ = { 167 | isa = XCBuildConfiguration; 168 | buildSettings = { 169 | ALWAYS_SEARCH_USER_PATHS = NO; 170 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 171 | CLANG_CXX_LIBRARY = "libc++"; 172 | CLANG_ENABLE_MODULES = YES; 173 | CLANG_ENABLE_OBJC_ARC = YES; 174 | CLANG_WARN_BOOL_CONVERSION = YES; 175 | CLANG_WARN_CONSTANT_CONVERSION = YES; 176 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 177 | CLANG_WARN_EMPTY_BODY = YES; 178 | CLANG_WARN_ENUM_CONVERSION = YES; 179 | CLANG_WARN_INFINITE_RECURSION = YES; 180 | CLANG_WARN_INT_CONVERSION = YES; 181 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 182 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 183 | CLANG_WARN_UNREACHABLE_CODE = YES; 184 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 185 | COPY_PHASE_STRIP = YES; 186 | ENABLE_NS_ASSERTIONS = NO; 187 | ENABLE_STRICT_OBJC_MSGSEND = YES; 188 | GCC_C_LANGUAGE_STANDARD = gnu99; 189 | GCC_NO_COMMON_BLOCKS = YES; 190 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 191 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 192 | GCC_WARN_UNDECLARED_SELECTOR = YES; 193 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 194 | GCC_WARN_UNUSED_FUNCTION = YES; 195 | GCC_WARN_UNUSED_VARIABLE = YES; 196 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 197 | MTL_ENABLE_DEBUG_INFO = NO; 198 | SDKROOT = iphoneos; 199 | VALIDATE_PRODUCT = YES; 200 | }; 201 | name = Release; 202 | }; 203 | 58B511F01A9E6C8500147676 /* Debug */ = { 204 | isa = XCBuildConfiguration; 205 | buildSettings = { 206 | HEADER_SEARCH_PATHS = ( 207 | "$(inherited)", 208 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 209 | "$(SRCROOT)/../../../React/**", 210 | "$(SRCROOT)/../../react-native/React/**", 211 | ); 212 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 213 | OTHER_LDFLAGS = "-ObjC"; 214 | PRODUCT_NAME = RNAlarm; 215 | SKIP_INSTALL = YES; 216 | }; 217 | name = Debug; 218 | }; 219 | 58B511F11A9E6C8500147676 /* Release */ = { 220 | isa = XCBuildConfiguration; 221 | buildSettings = { 222 | HEADER_SEARCH_PATHS = ( 223 | "$(inherited)", 224 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 225 | "$(SRCROOT)/../../../React/**", 226 | "$(SRCROOT)/../../react-native/React/**", 227 | ); 228 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 229 | OTHER_LDFLAGS = "-ObjC"; 230 | PRODUCT_NAME = RNAlarm; 231 | SKIP_INSTALL = YES; 232 | }; 233 | name = Release; 234 | }; 235 | /* End XCBuildConfiguration section */ 236 | 237 | /* Begin XCConfigurationList section */ 238 | 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNAlarm" */ = { 239 | isa = XCConfigurationList; 240 | buildConfigurations = ( 241 | 58B511ED1A9E6C8500147676 /* Debug */, 242 | 58B511EE1A9E6C8500147676 /* Release */, 243 | ); 244 | defaultConfigurationIsVisible = 0; 245 | defaultConfigurationName = Release; 246 | }; 247 | 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNAlarm" */ = { 248 | isa = XCConfigurationList; 249 | buildConfigurations = ( 250 | 58B511F01A9E6C8500147676 /* Debug */, 251 | 58B511F11A9E6C8500147676 /* Release */, 252 | ); 253 | defaultConfigurationIsVisible = 0; 254 | defaultConfigurationName = Release; 255 | }; 256 | /* End XCConfigurationList section */ 257 | }; 258 | rootObject = 58B511D31A9E6C8500147676 /* Project object */; 259 | } 260 | -------------------------------------------------------------------------------- /ios/RNAlarm.m: -------------------------------------------------------------------------------- 1 | 2 | #import "RNAlarm.h" 3 | #import 4 | #import 5 | 6 | @implementation RNAlarm 7 | //AVAudioPlayer *audioPlay; 8 | 9 | -(void) setAlarm: (NSString *) triggerTime andStatus: (NSString * ) status{ 10 | NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults]; 11 | [userDefault setObject:status forKey:triggerTime]; 12 | [userDefault synchronize]; 13 | } 14 | 15 | 16 | -(int) getAlarmStatus: (NSString *) triggerTime{ 17 | NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults]; 18 | NSString *strStatus = [userDefault objectForKey:triggerTime]; 19 | 20 | if (strStatus == nil) { 21 | return -1; 22 | }else{ 23 | return [strStatus isEqualToString:@"error"] ? NO : YES; 24 | } 25 | } 26 | 27 | //- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler{ 28 | // completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound); 29 | // AVAudioSession *session = [AVAudioSession sharedInstance]; 30 | // [session setCategory:AVAudioSessionCategoryPlayback error:nil]; 31 | // [session setActive:YES error:nil]; 32 | // 33 | // NSURL *fileURL = [NSURL fileURLWithPath:@"/Library/Ringtones/Constellation.m4r"]; 34 | // audioPlay = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil]; 35 | // audioPlay.numberOfLoops = -1; 36 | // [audioPlay play]; 37 | 38 | 39 | //} 40 | -(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler{ 41 | 42 | completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound); 43 | 44 | AudioServicesPlayAlertSoundWithCompletion(kSystemSoundID_Vibrate, nil); 45 | } 46 | 47 | -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler{ 48 | // if(response.actionIdentifier == @"clear.repeat.action") { 49 | 50 | NSString *categoryIdentifier = response.notification.request.content.categoryIdentifier; 51 | NSString *identifier1 = [categoryIdentifier stringByAppendingString:@"1"]; 52 | NSString *identifier2 = [categoryIdentifier stringByAppendingString:@"2"]; 53 | NSString *identifier3 = [categoryIdentifier stringByAppendingString:@"3"]; 54 | 55 | [center removePendingNotificationRequestsWithIdentifiers:@[identifier1,identifier2,identifier3]]; 56 | [center removeDeliveredNotificationsWithIdentifiers:@[identifier1,identifier2,identifier3]]; 57 | //[audioPlay stop]; 58 | //[center removeAllPendingNotificationRequests]; 59 | //} 60 | 61 | completionHandler(); 62 | } 63 | //-(void)playSound() { 64 | //// NSString *soundFilePath = [NSString stringWithFormat:@"%@/Constellation.m4r", [[NSBundle mainBundle] resourcePath]]; 65 | //// NSURL *fileURL =[[NSURL alloc] initFileURLWithPath:soundFilePath]; 66 | // NSURL *from = [NSURL fileURLWithPath:@"/Library/Ringtones/Constellation.m4r"]; 67 | // AVAudioPlayer *audioPlay = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil]; 68 | // audioPlay.numberOfLoops = -1; 69 | // [audioPlay play]; 70 | //} 71 | - (dispatch_queue_t)methodQueue 72 | { 73 | return dispatch_get_main_queue(); 74 | } 75 | RCT_EXPORT_MODULE() 76 | 77 | // Thanks, AshFurrow 78 | static const unsigned componentFlags = (NSCalendarUnitYear| NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitWeekday | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitWeekday | NSCalendarUnitWeekdayOrdinal); 79 | 80 | RCT_EXPORT_METHOD(playTipSound: (NSString*) fileName){ 81 | 82 | NSString *soundPath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"m4r"]; 83 | SystemSoundID soundID = 0; 84 | NSURL *url = [NSURL fileURLWithPath:soundPath]; 85 | AudioServicesCreateSystemSoundID(CFBridgingRetain(url), &soundID); 86 | AudioServicesPlaySystemSound (soundID); 87 | } 88 | 89 | RCT_EXPORT_METHOD(clearAlarm){ 90 | NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults]; 91 | NSDictionary *dic = [userDefault dictionaryRepresentation]; 92 | for (id key in dic) { 93 | [userDefault removeObjectForKey:key]; 94 | } 95 | [userDefault synchronize]; 96 | [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; 97 | [[UIApplication sharedApplication] cancelAllLocalNotifications]; 98 | } 99 | 100 | 101 | 102 | RCT_EXPORT_METHOD(initAlarm: successCallback:(RCTResponseSenderBlock)callback){ 103 | 104 | UNUserNotificationCenter *rCenter = UNUserNotificationCenter.currentNotificationCenter; 105 | [rCenter requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound) 106 | completionHandler:^(BOOL granted, NSError * _Nullable error){ 107 | // Enable or disable based on authorization 108 | if (granted == YES) { 109 | NSArray *result = [NSArray arrayWithObjects:[NSNumber numberWithBool:NO], nil]; 110 | if(successCallback != nil){ 111 | result = [NSArray arrayWithObjects:[NSNumber numberWithBool:YES], nil]; 112 | } 113 | callback(result); 114 | } 115 | }]; 116 | } 117 | 118 | RCT_EXPORT_METHOD(setAlarm:(NSString *)triggerTime 119 | title:(NSString *)title 120 | isRetry:(NSString *)isRetry 121 | musicUri:(NSString *)musicUri 122 | successCallback:(RCTResponseSenderBlock)successCallback 123 | errorCallback:(RCTResponseSenderBlock)errorCallback){ 124 | @try 125 | { 126 | // NSURL *url = [NSURL URLWithString:@"Clock-alarm:"]; 127 | // if ([[UIApplication sharedApplication] canOpenURL:url]) { 128 | // [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; 129 | // } 130 | 131 | //得到闹钟在本机中的设置状态,-1为没有此闹钟 132 | int alarmStatus = [self getAlarmStatus:triggerTime]; 133 | //强制设置闹钟,更新本机闹钟状态为nil 134 | if (isRetry != nil && ![isRetry isEqual: @""]) { 135 | [self setAlarm:triggerTime andStatus:nil]; 136 | } 137 | 138 | bool isSettedAlarm = [NSNumber numberWithInt:alarmStatus].boolValue; 139 | //闹钟已经设定过了,并且是设置失败了,不再设置此闹钟,直接退出此次设置 140 | if (alarmStatus != -1) 141 | { 142 | //闹钟已经设置过了,不再重复设置 143 | if (isSettedAlarm) { 144 | NSArray *result = [NSArray arrayWithObjects:@"0", nil]; 145 | if(successCallback != nil){ 146 | successCallback(result); 147 | return; 148 | } 149 | } 150 | else 151 | { 152 | NSArray *result = [NSArray arrayWithObjects:@"0",nil]; 153 | if(errorCallback != nil) { 154 | errorCallback(result); 155 | return; 156 | } 157 | } 158 | } 159 | 160 | UNUserNotificationCenter *rCenter = UNUserNotificationCenter.currentNotificationCenter; 161 | [rCenter requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound) 162 | completionHandler:^(BOOL granted, NSError * _Nullable error){ 163 | // Enable or disable based on authorization 164 | }]; 165 | 166 | 167 | UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; 168 | //content.title = [NSString localizedUserNotificationStringForKey:@"RNALarm" arguments:nil]; 169 | content.body = [NSString localizedUserNotificationStringForKey:title arguments:nil]; 170 | //content.categoryIdentifier = @"RNAlarmCategory"; 171 | content.categoryIdentifier = triggerTime; 172 | 173 | musicUri = @"Constellation.m4r"; 174 | if(musicUri == nil) { 175 | content.sound = [UNNotificationSound defaultSound]; 176 | }else { 177 | NSFileManager *fileManage = NSFileManager.defaultManager; 178 | 179 | NSURL *libraryUrl = [[fileManage URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] objectAtIndex:0]; 180 | NSURL *soundDirUrl = [libraryUrl URLByAppendingPathComponent:@"Sounds"]; 181 | [fileManage createDirectoryAtURL:soundDirUrl withIntermediateDirectories:TRUE attributes:nil error:nil]; 182 | 183 | NSURL *from = [NSURL fileURLWithPath:@"/Library/Ringtones/Constellation.m4r"]; 184 | NSURL *dest = [soundDirUrl URLByAppendingPathComponent:musicUri]; 185 | [fileManage copyItemAtURL:from toURL:dest error:nil]; 186 | 187 | content.sound = [UNNotificationSound soundNamed:musicUri]; 188 | } 189 | // NSTimeInterval time =[triggerTime doubleValue]; 190 | // 191 | // NSDate *tgTime = [NSDate dateWithTimeIntervalSinceNow:time]; 192 | 193 | 194 | 195 | // NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 196 | // NSDateComponents *components =[gregorian components:componentFlags fromDate:tgTime]; 197 | // 198 | // UNCalendarNotificationTrigger *trigger1 = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:NO]; 199 | 200 | // current date 201 | NSDate *date = [NSDate date]; 202 | double nowSeconds = [date timeIntervalSince1970]; 203 | 204 | double startDate =[triggerTime doubleValue]; 205 | 206 | double intervalSeconds = startDate/1000 - nowSeconds; 207 | //NSTimeInterval time =[triggerTime doubleValue]; 208 | if (intervalSeconds > 0) { 209 | 210 | //for (int i=0; i<3; i++) { 211 | UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:intervalSeconds repeats:NO]; 212 | 213 | UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier: [triggerTime stringByAppendingString: @"1"] content:content trigger:trigger]; 214 | 215 | UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; 216 | 217 | //NSArray *actionOption = [NSArray arrayWithObject:@"actionOption"]; 218 | 219 | UNNotificationAction *action = [UNNotificationAction 220 | actionWithIdentifier:@"clear.repeat.action" 221 | title:@"关闭" 222 | options:UNNotificationActionOptionForeground]; 223 | UNNotificationCategory *category = [UNNotificationCategory 224 | //categoryWithIdentifier:@"RNAlarmCategory" 225 | categoryWithIdentifier:triggerTime 226 | actions:@[action] 227 | intentIdentifiers:@[] 228 | options:UNNotificationCategoryOptionCustomDismissAction]; 229 | 230 | [center setNotificationCategories: [NSSet setWithObjects:category, nil]]; 231 | [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { 232 | if(error != nil) 233 | { 234 | // NSLog(error.localizedDescription); 235 | @throw error; 236 | } 237 | }]; 238 | 239 | center.delegate = self; 240 | //intervalSeconds += 60; 241 | //} 242 | [self setAlarm:triggerTime andStatus:@"success"]; 243 | 244 | NSArray *result = [NSArray arrayWithObjects:@"0", nil]; 245 | if(successCallback != nil){ 246 | successCallback(result); 247 | } 248 | } 249 | else{ 250 | [self setAlarm:triggerTime andStatus:@"error"]; 251 | 252 | NSArray *result = [NSArray arrayWithObjects:@"0",nil]; 253 | if(errorCallback != nil) { 254 | errorCallback(result); 255 | } 256 | } 257 | 258 | 259 | 260 | } 261 | @catch(NSException *exception){ 262 | NSLog(@"%@", exception.reason); 263 | NSArray *result = [NSArray arrayWithObjects:@"1",exception.reason, nil]; 264 | if(errorCallback != nil) { 265 | errorCallback(result); 266 | } 267 | } 268 | } 269 | 270 | 271 | 272 | RCT_EXPORT_METHOD(setAlarmWithPromise:(NSString *)triggerTime 273 | title:(NSString *)title 274 | musicUri:(nullable NSString *)musicUri 275 | resolver:(RCTPromiseResolveBlock)resolver 276 | reject:(RCTPromiseRejectBlock)reject){ 277 | @try 278 | { 279 | UNUserNotificationCenter *rCenter = UNUserNotificationCenter.currentNotificationCenter; 280 | [rCenter requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound) 281 | completionHandler:^(BOOL granted, NSError * _Nullable error){ 282 | // Enable or disable based on authorization 283 | }]; 284 | 285 | UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; 286 | //content.title = [NSString localizedUserNotificationStringForKey:@"RNALarm" arguments:nil]; 287 | content.body = [NSString localizedUserNotificationStringForKey:title arguments:nil]; 288 | if(musicUri == nil) { 289 | content.sound = [UNNotificationSound defaultSound]; 290 | }else { 291 | content.sound = [UNNotificationSound soundNamed:musicUri]; 292 | } 293 | NSTimeInterval time =[triggerTime doubleValue]; 294 | NSDate *tgTime = [NSDate dateWithTimeIntervalSince1970:time]; 295 | NSDateComponents *components = [[NSCalendar autoupdatingCurrentCalendar] components:componentFlags fromDate:tgTime]; 296 | UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:NO]; 297 | 298 | UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"RNAlarm" content:content trigger:trigger]; 299 | UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; 300 | [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { 301 | if(error != nil) 302 | { 303 | // NSLog(error.localizedDescription); 304 | @throw error; 305 | } 306 | }]; 307 | 308 | NSArray *result = [NSArray arrayWithObjects:@"0", nil]; 309 | resolver(result); 310 | } 311 | @catch(NSException *exception){ 312 | NSLog(@"%@", exception.reason); 313 | NSError *error = [[NSError alloc] init]; 314 | 315 | reject(@"RNAlarm_Errror", exception.name, error); 316 | } 317 | } 318 | 319 | @end 320 | 321 | 322 | --------------------------------------------------------------------------------