├── .gitignore ├── RNRecordAudio ├── RNRecordAudio.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── rossbeinhaker.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── rossbeinhaker.xcuserdatad │ │ └── xcschemes │ │ └── RNRecordAudio.xcscheme ├── RNRecordAudio │ ├── RNRecordAudio.h │ └── RNRecordAudio.m ├── RNRecordAudioTests │ └── Info.plist └── package.json ├── example.ios.js └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # node.js 26 | # 27 | node_modules/ 28 | npm-debug.log 29 | -------------------------------------------------------------------------------- /RNRecordAudio/RNRecordAudio.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | DFC145791BAB2BA0008BCF87 /* RNRecordAudio.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DFC145781BAB2BA0008BCF87 /* RNRecordAudio.h */; }; 11 | DFC1457B1BAB2BA0008BCF87 /* RNRecordAudio.m in Sources */ = {isa = PBXBuildFile; fileRef = DFC1457A1BAB2BA0008BCF87 /* RNRecordAudio.m */; }; 12 | DFC145811BAB2BA0008BCF87 /* libRNRecordAudio.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DFC145751BAB2BA0008BCF87 /* libRNRecordAudio.a */; }; 13 | /* End PBXBuildFile section */ 14 | 15 | /* Begin PBXContainerItemProxy section */ 16 | DFC145821BAB2BA0008BCF87 /* PBXContainerItemProxy */ = { 17 | isa = PBXContainerItemProxy; 18 | containerPortal = DFC1456D1BAB2BA0008BCF87 /* Project object */; 19 | proxyType = 1; 20 | remoteGlobalIDString = DFC145741BAB2BA0008BCF87; 21 | remoteInfo = RNRecordAudio; 22 | }; 23 | /* End PBXContainerItemProxy section */ 24 | 25 | /* Begin PBXCopyFilesBuildPhase section */ 26 | DFC145731BAB2BA0008BCF87 /* CopyFiles */ = { 27 | isa = PBXCopyFilesBuildPhase; 28 | buildActionMask = 2147483647; 29 | dstPath = "include/$(PRODUCT_NAME)"; 30 | dstSubfolderSpec = 16; 31 | files = ( 32 | DFC145791BAB2BA0008BCF87 /* RNRecordAudio.h in CopyFiles */, 33 | ); 34 | runOnlyForDeploymentPostprocessing = 0; 35 | }; 36 | /* End PBXCopyFilesBuildPhase section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | DFC145751BAB2BA0008BCF87 /* libRNRecordAudio.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNRecordAudio.a; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | DFC145781BAB2BA0008BCF87 /* RNRecordAudio.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNRecordAudio.h; sourceTree = ""; }; 41 | DFC1457A1BAB2BA0008BCF87 /* RNRecordAudio.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNRecordAudio.m; sourceTree = ""; }; 42 | DFC145801BAB2BA0008BCF87 /* RNRecordAudioTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RNRecordAudioTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | DFC145861BAB2BA0008BCF87 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 44 | /* End PBXFileReference section */ 45 | 46 | /* Begin PBXFrameworksBuildPhase section */ 47 | DFC145721BAB2BA0008BCF87 /* Frameworks */ = { 48 | isa = PBXFrameworksBuildPhase; 49 | buildActionMask = 2147483647; 50 | files = ( 51 | ); 52 | runOnlyForDeploymentPostprocessing = 0; 53 | }; 54 | DFC1457D1BAB2BA0008BCF87 /* Frameworks */ = { 55 | isa = PBXFrameworksBuildPhase; 56 | buildActionMask = 2147483647; 57 | files = ( 58 | DFC145811BAB2BA0008BCF87 /* libRNRecordAudio.a in Frameworks */, 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXFrameworksBuildPhase section */ 63 | 64 | /* Begin PBXGroup section */ 65 | DFC1456C1BAB2BA0008BCF87 = { 66 | isa = PBXGroup; 67 | children = ( 68 | DFC145771BAB2BA0008BCF87 /* RNRecordAudio */, 69 | DFC145841BAB2BA0008BCF87 /* RNRecordAudioTests */, 70 | DFC145761BAB2BA0008BCF87 /* Products */, 71 | ); 72 | sourceTree = ""; 73 | }; 74 | DFC145761BAB2BA0008BCF87 /* Products */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | DFC145751BAB2BA0008BCF87 /* libRNRecordAudio.a */, 78 | DFC145801BAB2BA0008BCF87 /* RNRecordAudioTests.xctest */, 79 | ); 80 | name = Products; 81 | sourceTree = ""; 82 | }; 83 | DFC145771BAB2BA0008BCF87 /* RNRecordAudio */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | DFC145781BAB2BA0008BCF87 /* RNRecordAudio.h */, 87 | DFC1457A1BAB2BA0008BCF87 /* RNRecordAudio.m */, 88 | ); 89 | path = RNRecordAudio; 90 | sourceTree = ""; 91 | }; 92 | DFC145841BAB2BA0008BCF87 /* RNRecordAudioTests */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | DFC145851BAB2BA0008BCF87 /* Supporting Files */, 96 | ); 97 | path = RNRecordAudioTests; 98 | sourceTree = ""; 99 | }; 100 | DFC145851BAB2BA0008BCF87 /* Supporting Files */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | DFC145861BAB2BA0008BCF87 /* Info.plist */, 104 | ); 105 | name = "Supporting Files"; 106 | sourceTree = ""; 107 | }; 108 | /* End PBXGroup section */ 109 | 110 | /* Begin PBXNativeTarget section */ 111 | DFC145741BAB2BA0008BCF87 /* RNRecordAudio */ = { 112 | isa = PBXNativeTarget; 113 | buildConfigurationList = DFC145891BAB2BA0008BCF87 /* Build configuration list for PBXNativeTarget "RNRecordAudio" */; 114 | buildPhases = ( 115 | DFC145711BAB2BA0008BCF87 /* Sources */, 116 | DFC145721BAB2BA0008BCF87 /* Frameworks */, 117 | DFC145731BAB2BA0008BCF87 /* CopyFiles */, 118 | ); 119 | buildRules = ( 120 | ); 121 | dependencies = ( 122 | ); 123 | name = RNRecordAudio; 124 | productName = RNRecordAudio; 125 | productReference = DFC145751BAB2BA0008BCF87 /* libRNRecordAudio.a */; 126 | productType = "com.apple.product-type.library.static"; 127 | }; 128 | DFC1457F1BAB2BA0008BCF87 /* RNRecordAudioTests */ = { 129 | isa = PBXNativeTarget; 130 | buildConfigurationList = DFC1458C1BAB2BA0008BCF87 /* Build configuration list for PBXNativeTarget "RNRecordAudioTests" */; 131 | buildPhases = ( 132 | DFC1457C1BAB2BA0008BCF87 /* Sources */, 133 | DFC1457D1BAB2BA0008BCF87 /* Frameworks */, 134 | DFC1457E1BAB2BA0008BCF87 /* Resources */, 135 | ); 136 | buildRules = ( 137 | ); 138 | dependencies = ( 139 | DFC145831BAB2BA0008BCF87 /* PBXTargetDependency */, 140 | ); 141 | name = RNRecordAudioTests; 142 | productName = RNRecordAudioTests; 143 | productReference = DFC145801BAB2BA0008BCF87 /* RNRecordAudioTests.xctest */; 144 | productType = "com.apple.product-type.bundle.unit-test"; 145 | }; 146 | /* End PBXNativeTarget section */ 147 | 148 | /* Begin PBXProject section */ 149 | DFC1456D1BAB2BA0008BCF87 /* Project object */ = { 150 | isa = PBXProject; 151 | attributes = { 152 | LastUpgradeCheck = 0640; 153 | ORGANIZATIONNAME = rhaker; 154 | TargetAttributes = { 155 | DFC145741BAB2BA0008BCF87 = { 156 | CreatedOnToolsVersion = 6.4; 157 | }; 158 | DFC1457F1BAB2BA0008BCF87 = { 159 | CreatedOnToolsVersion = 6.4; 160 | }; 161 | }; 162 | }; 163 | buildConfigurationList = DFC145701BAB2BA0008BCF87 /* Build configuration list for PBXProject "RNRecordAudio" */; 164 | compatibilityVersion = "Xcode 3.2"; 165 | developmentRegion = English; 166 | hasScannedForEncodings = 0; 167 | knownRegions = ( 168 | en, 169 | ); 170 | mainGroup = DFC1456C1BAB2BA0008BCF87; 171 | productRefGroup = DFC145761BAB2BA0008BCF87 /* Products */; 172 | projectDirPath = ""; 173 | projectRoot = ""; 174 | targets = ( 175 | DFC145741BAB2BA0008BCF87 /* RNRecordAudio */, 176 | DFC1457F1BAB2BA0008BCF87 /* RNRecordAudioTests */, 177 | ); 178 | }; 179 | /* End PBXProject section */ 180 | 181 | /* Begin PBXResourcesBuildPhase section */ 182 | DFC1457E1BAB2BA0008BCF87 /* Resources */ = { 183 | isa = PBXResourcesBuildPhase; 184 | buildActionMask = 2147483647; 185 | files = ( 186 | ); 187 | runOnlyForDeploymentPostprocessing = 0; 188 | }; 189 | /* End PBXResourcesBuildPhase section */ 190 | 191 | /* Begin PBXSourcesBuildPhase section */ 192 | DFC145711BAB2BA0008BCF87 /* Sources */ = { 193 | isa = PBXSourcesBuildPhase; 194 | buildActionMask = 2147483647; 195 | files = ( 196 | DFC1457B1BAB2BA0008BCF87 /* RNRecordAudio.m in Sources */, 197 | ); 198 | runOnlyForDeploymentPostprocessing = 0; 199 | }; 200 | DFC1457C1BAB2BA0008BCF87 /* Sources */ = { 201 | isa = PBXSourcesBuildPhase; 202 | buildActionMask = 2147483647; 203 | files = ( 204 | ); 205 | runOnlyForDeploymentPostprocessing = 0; 206 | }; 207 | /* End PBXSourcesBuildPhase section */ 208 | 209 | /* Begin PBXTargetDependency section */ 210 | DFC145831BAB2BA0008BCF87 /* PBXTargetDependency */ = { 211 | isa = PBXTargetDependency; 212 | target = DFC145741BAB2BA0008BCF87 /* RNRecordAudio */; 213 | targetProxy = DFC145821BAB2BA0008BCF87 /* PBXContainerItemProxy */; 214 | }; 215 | /* End PBXTargetDependency section */ 216 | 217 | /* Begin XCBuildConfiguration section */ 218 | DFC145871BAB2BA0008BCF87 /* Debug */ = { 219 | isa = XCBuildConfiguration; 220 | buildSettings = { 221 | ALWAYS_SEARCH_USER_PATHS = NO; 222 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 223 | CLANG_CXX_LIBRARY = "libc++"; 224 | CLANG_ENABLE_MODULES = YES; 225 | CLANG_ENABLE_OBJC_ARC = YES; 226 | CLANG_WARN_BOOL_CONVERSION = YES; 227 | CLANG_WARN_CONSTANT_CONVERSION = YES; 228 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 229 | CLANG_WARN_EMPTY_BODY = YES; 230 | CLANG_WARN_ENUM_CONVERSION = YES; 231 | CLANG_WARN_INT_CONVERSION = YES; 232 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 233 | CLANG_WARN_UNREACHABLE_CODE = YES; 234 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 235 | COPY_PHASE_STRIP = NO; 236 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 237 | ENABLE_STRICT_OBJC_MSGSEND = YES; 238 | GCC_C_LANGUAGE_STANDARD = gnu99; 239 | GCC_DYNAMIC_NO_PIC = NO; 240 | GCC_NO_COMMON_BLOCKS = YES; 241 | GCC_OPTIMIZATION_LEVEL = 0; 242 | GCC_PREPROCESSOR_DEFINITIONS = ( 243 | "DEBUG=1", 244 | "$(inherited)", 245 | ); 246 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 247 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 248 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 249 | GCC_WARN_UNDECLARED_SELECTOR = YES; 250 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 251 | GCC_WARN_UNUSED_FUNCTION = YES; 252 | GCC_WARN_UNUSED_VARIABLE = YES; 253 | HEADER_SEARCH_PATHS = ( 254 | "$(inherited)", 255 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 256 | "$(SRCROOT)/node_modules/react-native/React/**", 257 | "$(SRCROOT)/../react-native/React/**", 258 | ); 259 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 260 | MTL_ENABLE_DEBUG_INFO = YES; 261 | ONLY_ACTIVE_ARCH = YES; 262 | SDKROOT = iphoneos; 263 | }; 264 | name = Debug; 265 | }; 266 | DFC145881BAB2BA0008BCF87 /* Release */ = { 267 | isa = XCBuildConfiguration; 268 | buildSettings = { 269 | ALWAYS_SEARCH_USER_PATHS = NO; 270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 271 | CLANG_CXX_LIBRARY = "libc++"; 272 | CLANG_ENABLE_MODULES = YES; 273 | CLANG_ENABLE_OBJC_ARC = YES; 274 | CLANG_WARN_BOOL_CONVERSION = YES; 275 | CLANG_WARN_CONSTANT_CONVERSION = YES; 276 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 277 | CLANG_WARN_EMPTY_BODY = YES; 278 | CLANG_WARN_ENUM_CONVERSION = YES; 279 | CLANG_WARN_INT_CONVERSION = YES; 280 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 281 | CLANG_WARN_UNREACHABLE_CODE = YES; 282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 283 | COPY_PHASE_STRIP = NO; 284 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 285 | ENABLE_NS_ASSERTIONS = NO; 286 | ENABLE_STRICT_OBJC_MSGSEND = YES; 287 | GCC_C_LANGUAGE_STANDARD = gnu99; 288 | GCC_NO_COMMON_BLOCKS = YES; 289 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 290 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 291 | GCC_WARN_UNDECLARED_SELECTOR = YES; 292 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 293 | GCC_WARN_UNUSED_FUNCTION = YES; 294 | GCC_WARN_UNUSED_VARIABLE = YES; 295 | HEADER_SEARCH_PATHS = ( 296 | "$(inherited)", 297 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 298 | "$(SRCROOT)/node_modules/react-native/React/**", 299 | "$(SRCROOT)/../react-native/React/**", 300 | ); 301 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 302 | MTL_ENABLE_DEBUG_INFO = NO; 303 | SDKROOT = iphoneos; 304 | VALIDATE_PRODUCT = YES; 305 | }; 306 | name = Release; 307 | }; 308 | DFC1458A1BAB2BA0008BCF87 /* Debug */ = { 309 | isa = XCBuildConfiguration; 310 | buildSettings = { 311 | HEADER_SEARCH_PATHS = ( 312 | "$(inherited)", 313 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 314 | "$(SRCROOT)/node_modules/react-native/React/**", 315 | "$(SRCROOT)/../react-native/React/**", 316 | ); 317 | OTHER_LDFLAGS = "-ObjC"; 318 | PRODUCT_NAME = "$(TARGET_NAME)"; 319 | SKIP_INSTALL = YES; 320 | }; 321 | name = Debug; 322 | }; 323 | DFC1458B1BAB2BA0008BCF87 /* Release */ = { 324 | isa = XCBuildConfiguration; 325 | buildSettings = { 326 | HEADER_SEARCH_PATHS = ( 327 | "$(inherited)", 328 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 329 | "$(SRCROOT)/node_modules/react-native/React/**", 330 | "$(SRCROOT)/../react-native/React/**", 331 | ); 332 | OTHER_LDFLAGS = "-ObjC"; 333 | PRODUCT_NAME = "$(TARGET_NAME)"; 334 | SKIP_INSTALL = YES; 335 | }; 336 | name = Release; 337 | }; 338 | DFC1458D1BAB2BA0008BCF87 /* Debug */ = { 339 | isa = XCBuildConfiguration; 340 | buildSettings = { 341 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 342 | FRAMEWORK_SEARCH_PATHS = ( 343 | "$(SDKROOT)/Developer/Library/Frameworks", 344 | "$(inherited)", 345 | ); 346 | GCC_PREPROCESSOR_DEFINITIONS = ( 347 | "DEBUG=1", 348 | "$(inherited)", 349 | ); 350 | INFOPLIST_FILE = RNRecordAudioTests/Info.plist; 351 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 352 | PRODUCT_NAME = "$(TARGET_NAME)"; 353 | }; 354 | name = Debug; 355 | }; 356 | DFC1458E1BAB2BA0008BCF87 /* Release */ = { 357 | isa = XCBuildConfiguration; 358 | buildSettings = { 359 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 360 | FRAMEWORK_SEARCH_PATHS = ( 361 | "$(SDKROOT)/Developer/Library/Frameworks", 362 | "$(inherited)", 363 | ); 364 | INFOPLIST_FILE = RNRecordAudioTests/Info.plist; 365 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 366 | PRODUCT_NAME = "$(TARGET_NAME)"; 367 | }; 368 | name = Release; 369 | }; 370 | /* End XCBuildConfiguration section */ 371 | 372 | /* Begin XCConfigurationList section */ 373 | DFC145701BAB2BA0008BCF87 /* Build configuration list for PBXProject "RNRecordAudio" */ = { 374 | isa = XCConfigurationList; 375 | buildConfigurations = ( 376 | DFC145871BAB2BA0008BCF87 /* Debug */, 377 | DFC145881BAB2BA0008BCF87 /* Release */, 378 | ); 379 | defaultConfigurationIsVisible = 0; 380 | defaultConfigurationName = Release; 381 | }; 382 | DFC145891BAB2BA0008BCF87 /* Build configuration list for PBXNativeTarget "RNRecordAudio" */ = { 383 | isa = XCConfigurationList; 384 | buildConfigurations = ( 385 | DFC1458A1BAB2BA0008BCF87 /* Debug */, 386 | DFC1458B1BAB2BA0008BCF87 /* Release */, 387 | ); 388 | defaultConfigurationIsVisible = 0; 389 | }; 390 | DFC1458C1BAB2BA0008BCF87 /* Build configuration list for PBXNativeTarget "RNRecordAudioTests" */ = { 391 | isa = XCConfigurationList; 392 | buildConfigurations = ( 393 | DFC1458D1BAB2BA0008BCF87 /* Debug */, 394 | DFC1458E1BAB2BA0008BCF87 /* Release */, 395 | ); 396 | defaultConfigurationIsVisible = 0; 397 | }; 398 | /* End XCConfigurationList section */ 399 | }; 400 | rootObject = DFC1456D1BAB2BA0008BCF87 /* Project object */; 401 | } 402 | -------------------------------------------------------------------------------- /RNRecordAudio/RNRecordAudio.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RNRecordAudio/RNRecordAudio.xcodeproj/project.xcworkspace/xcuserdata/rossbeinhaker.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhaker/react-native-record-audio-ios/cbd294f5ca2ff6c21926326a8a110aa1136640e9/RNRecordAudio/RNRecordAudio.xcodeproj/project.xcworkspace/xcuserdata/rossbeinhaker.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /RNRecordAudio/RNRecordAudio.xcodeproj/xcuserdata/rossbeinhaker.xcuserdatad/xcschemes/RNRecordAudio.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /RNRecordAudio/RNRecordAudio/RNRecordAudio.h: -------------------------------------------------------------------------------- 1 | // 2 | // RNRecordAudio.h 3 | // RNRecordAudio 4 | // Created by Ross Haker on 9/13/15. 5 | // 6 | 7 | 8 | #import 9 | #import 10 | 11 | @interface RNRecordAudio : NSObject 12 | 13 | @end -------------------------------------------------------------------------------- /RNRecordAudio/RNRecordAudio/RNRecordAudio.m: -------------------------------------------------------------------------------- 1 | // 2 | // RNRecordAudio.m 3 | // RNRecordAudio 4 | // Created by Ross Haker on 9/13/15. 5 | // 6 | 7 | #import "RNRecordAudio.h" 8 | 9 | @implementation RNRecordAudio { 10 | 11 | AVAudioSession *recordSession; 12 | AVAudioRecorder *audioRecorder; 13 | 14 | } 15 | 16 | // Expose this module to the React Native bridge 17 | RCT_EXPORT_MODULE() 18 | 19 | // Persist data 20 | RCT_EXPORT_METHOD(startRecord:(NSString *)fileName 21 | errorCallback:(RCTResponseSenderBlock)failureCallback 22 | callback:(RCTResponseSenderBlock)successCallback) { 23 | 24 | // Validate the file name has positive length 25 | if ([fileName length] < 1) { 26 | 27 | // Show failure message 28 | NSDictionary *resultsDict = @{ 29 | @"success" : @NO, 30 | @"errMsg" : @"Your file does not have a name." 31 | }; 32 | 33 | // Javascript error handling 34 | failureCallback(@[resultsDict]); 35 | return; 36 | 37 | } 38 | 39 | // Validate the file name has an extension 40 | NSRange isRange = [fileName rangeOfString:@"." options:NSCaseInsensitiveSearch]; 41 | 42 | if(isRange.location == 0) { 43 | 44 | // Show failure message 45 | NSDictionary *resultsDict = @{ 46 | @"success" : @NO, 47 | @"errMsg" : @"Your file does not have a valid name and extension." 48 | }; 49 | 50 | // Javascript error handling 51 | failureCallback(@[resultsDict]); 52 | return; 53 | 54 | } else { 55 | 56 | if(isRange.location == NSNotFound) { 57 | 58 | // Show failure message 59 | NSDictionary *resultsDict = @{ 60 | @"success" : @NO, 61 | @"errMsg" : @"Your file does not have a valid extension." 62 | }; 63 | 64 | // Javascript error handling 65 | failureCallback(@[resultsDict]); 66 | return; 67 | } 68 | 69 | } 70 | 71 | // Validate for .caf, .mp3, .aac, , .wav, .aiff 72 | NSRange isRangeCaf = [fileName rangeOfString:@".caf" options:NSCaseInsensitiveSearch]; 73 | NSRange isRangeM4a = [fileName rangeOfString:@".m4a" options:NSCaseInsensitiveSearch]; 74 | NSRange isRangeWav = [fileName rangeOfString:@".wav" options:NSCaseInsensitiveSearch]; 75 | 76 | if ((isRangeCaf.location == NSNotFound) && (isRangeM4a.location == NSNotFound) && (isRangeWav.location == NSNotFound)) { 77 | 78 | // Show failure message 79 | NSDictionary *resultsDict = @{ 80 | @"success" : @NO, 81 | @"errMsg" : @"File should be either a .caf, .m4a, or .wav" 82 | }; 83 | 84 | // Javascript error handling 85 | failureCallback(@[resultsDict]); 86 | return; 87 | 88 | } 89 | 90 | // Create an array of directory Paths, to allow us to get the documents directory 91 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 92 | 93 | // The documents directory is the first item 94 | NSString *documentsDirectory = [paths objectAtIndex:0]; 95 | 96 | // Create the path that the file will be stored at 97 | NSString *pathForFile = [NSString stringWithFormat:@"%@/%@", documentsDirectory, fileName]; 98 | 99 | NSURL *audioFileURL = [NSURL fileURLWithPath:pathForFile]; 100 | 101 | NSDictionary *recordSettings; 102 | 103 | // Set the recording setting based on type of file 104 | if (isRangeCaf.location != NSNotFound) { 105 | 106 | // caf setttings 107 | recordSettings = [NSDictionary dictionaryWithObjectsAndKeys: 108 | [NSNumber numberWithInt:AVAudioQualityHigh], AVEncoderAudioQualityKey, 109 | [NSNumber numberWithInt:16], AVEncoderBitRateKey, 110 | [NSNumber numberWithInt: 2], AVNumberOfChannelsKey, 111 | [NSNumber numberWithFloat:44100.0], AVSampleRateKey, 112 | nil]; 113 | 114 | } else if (isRangeM4a.location != NSNotFound) { 115 | 116 | // m4a settings 117 | recordSettings = [NSDictionary dictionaryWithObjectsAndKeys: 118 | [NSNumber numberWithInt: kAudioFormatMPEG4AAC], AVFormatIDKey, 119 | [NSNumber numberWithFloat:16000.0], AVSampleRateKey, 120 | [NSNumber numberWithInt: 1], AVNumberOfChannelsKey, 121 | nil]; 122 | 123 | } else { 124 | 125 | // default to wav settings 126 | recordSettings = [NSDictionary dictionaryWithObjectsAndKeys: 127 | [NSNumber numberWithFloat:44100.0],AVSampleRateKey, 128 | [NSNumber numberWithInt:2],AVNumberOfChannelsKey, 129 | [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey, 130 | [NSNumber numberWithInt:kAudioFormatLinearPCM],AVFormatIDKey, 131 | [NSNumber numberWithBool:NO], AVLinearPCMIsFloatKey, 132 | [NSNumber numberWithBool:0], AVLinearPCMIsBigEndianKey, 133 | [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved, 134 | [NSData data], AVChannelLayoutKey, nil]; 135 | 136 | } 137 | 138 | // Initialize the session for the recording 139 | NSError *error = nil; 140 | recordSession = [AVAudioSession sharedInstance]; 141 | [recordSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; 142 | 143 | // Initialize new recorder if existing does not match url 144 | if(audioRecorder && ![audioRecorder.url isEqual: audioFileURL]) { 145 | 146 | audioRecorder = [[AVAudioRecorder alloc] 147 | initWithURL:audioFileURL 148 | settings:recordSettings 149 | error:&error]; 150 | 151 | audioRecorder.delegate = self; 152 | } 153 | 154 | // Initialize recorder if it does not exists 155 | if (!audioRecorder) { 156 | 157 | audioRecorder = [[AVAudioRecorder alloc] 158 | initWithURL:audioFileURL 159 | settings:recordSettings 160 | error:&error]; 161 | 162 | audioRecorder.delegate = self; 163 | } 164 | 165 | // Validate no errors in the session initialization 166 | if (error) { 167 | 168 | // Show failure message 169 | NSDictionary *resultsDict = @{ 170 | @"success" : @NO, 171 | @"errMsg" : [error localizedDescription] 172 | }; 173 | 174 | // Javascript error handling 175 | failureCallback(@[resultsDict]); 176 | return; 177 | 178 | } else { 179 | 180 | // prepare the recording 181 | [audioRecorder prepareToRecord]; 182 | 183 | } 184 | 185 | // if recording is in progress, stop 186 | if (audioRecorder.recording) { 187 | 188 | [audioRecorder stop]; 189 | [recordSession setActive:NO error:nil]; 190 | 191 | } 192 | 193 | // start recording 194 | [recordSession setActive:YES error:nil]; 195 | [audioRecorder record]; 196 | 197 | // Craft a success return message 198 | NSDictionary *resultsDict = @{ 199 | @"success" : @YES, 200 | @"successMsg" : @"Successfully started." 201 | }; 202 | 203 | // Call the JavaScript sucess handler 204 | successCallback(@[resultsDict]); 205 | 206 | } 207 | 208 | // Persist data 209 | RCT_EXPORT_METHOD(stopRecord:(NSString *) fileName 210 | errorCallback:(RCTResponseSenderBlock)failureCallback 211 | callback:(RCTResponseSenderBlock)successCallback) { 212 | 213 | // Create an array of directory Paths, to allow us to get the documents directory 214 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 215 | 216 | // The documents directory is the first item 217 | NSString *documentsDirectory = [paths objectAtIndex:0]; 218 | 219 | // Create the path that the file will be stored at 220 | NSString *pathForFile = [NSString stringWithFormat:@"%@/%@", documentsDirectory, fileName]; 221 | 222 | // Validate that the file exists 223 | NSFileManager *fileManager = [NSFileManager defaultManager]; 224 | 225 | // Check if file exists 226 | if (![fileManager fileExistsAtPath:pathForFile]){ 227 | 228 | // Show failure message 229 | NSDictionary *resultsDict = @{ 230 | @"success" : @NO, 231 | @"errMsg" : @"File does not exist in app documents directory." 232 | }; 233 | 234 | // Javascript error handling 235 | failureCallback(@[resultsDict]); 236 | return; 237 | 238 | } 239 | 240 | // Validate that session and recorder exist to stop 241 | if (recordSession && audioRecorder) { 242 | 243 | // if recording is in progress, stop 244 | if (audioRecorder.recording) { 245 | 246 | [audioRecorder stop]; 247 | [recordSession setActive:NO error:nil]; 248 | 249 | // Craft a success return message 250 | NSDictionary *resultsDict = @{ 251 | @"success" : @YES, 252 | @"successMsg" : @"Successfully stopped." 253 | }; 254 | 255 | // Call the JavaScript sucess handler 256 | successCallback(@[resultsDict]); 257 | return; 258 | 259 | } else { 260 | 261 | // Show failure message 262 | NSDictionary *resultsDict = @{ 263 | @"success" : @NO, 264 | @"errMsg" : @"Recording not in progress. Can not be stopped." 265 | }; 266 | 267 | // Javascript error handling 268 | failureCallback(@[resultsDict]); 269 | return; 270 | } 271 | 272 | } else { 273 | 274 | // Show failure message 275 | NSDictionary *resultsDict = @{ 276 | @"success" : @NO, 277 | @"errMsg" : @"Recording was not ever started. Can not be stopped." 278 | }; 279 | 280 | // Javascript error handling 281 | failureCallback(@[resultsDict]); 282 | return; 283 | 284 | } 285 | 286 | 287 | } 288 | 289 | @end 290 | 291 | -------------------------------------------------------------------------------- /RNRecordAudio/RNRecordAudioTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | rhaker.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /RNRecordAudio/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-record-audio-ios", 3 | "version": "0.2.1", 4 | "description": "A react-native interface for recording audio on an ios device. Supports .caf, .m4a, and .wav files.", 5 | "main": "index.ios.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "react-component", 11 | "react-native", 12 | "ios", 13 | "audio", 14 | "recording", 15 | "record", 16 | "caf", 17 | "m4a", 18 | "wav" 19 | ], 20 | "repository": { 21 | "type": "git", 22 | "url": "github.com:rhaker/react-native-record-audio-ios.git" 23 | }, 24 | "author": "rhaker (http://github.com/rhaker)", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/rhaker/react-native-record-audio-ios/issues" 28 | }, 29 | "homepage": "https://github.com/rhaker/react-native-record-audio-ios", 30 | "peerDependencies": { 31 | "react-native": ">=0.12.0" 32 | }, 33 | "devDependencies": {} 34 | } 35 | -------------------------------------------------------------------------------- /example.ios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | */ 5 | 'use strict'; 6 | 7 | var React = require('react-native'); 8 | var { NativeModules } = React; 9 | var { RNRecordAudio } = NativeModules; 10 | 11 | var { 12 | AppRegistry, 13 | StyleSheet, 14 | Text, 15 | TouchableHighlight, 16 | View, 17 | } = React; 18 | 19 | var testComp = React.createClass({ 20 | componentDidMount() { 21 | // no actions in mount 22 | }, 23 | startRecord: function() { 24 | console.log('in start'); 25 | RNRecordAudio.startRecord( 26 | "file.m4a", // fileName 27 | function errorCallback(results) { 28 | console.log('JS Error: ' + results['errMsg']); 29 | }, 30 | function successCallback(results) { 31 | console.log('JS Success: ' + results['successMsg']); 32 | } 33 | ); 34 | }, 35 | stopRecord: function() { 36 | console.log("in stop"); 37 | RNRecordAudio.stopRecord( 38 | "file.m4a", // fileName 39 | function errorCallback(results) { 40 | console.log('JS Error: ' + results['errMsg']); 41 | }, 42 | function successCallback(results) { 43 | console.log('JS Success: ' + results['successMsg']); 44 | } 45 | ); 46 | }, 47 | render: function() { 48 | return ( 49 | 50 | 51 | Check Audio Status - View Xcode Log 52 | 53 | 54 | 55 | Press to Start Recording 56 | 57 | 58 | 59 | 60 | Press to Stop Recording 61 | 62 | 63 | 64 | ); 65 | } 66 | }); 67 | 68 | var styles = StyleSheet.create({ 69 | container: { 70 | flex: 1, 71 | justifyContent: 'center', 72 | alignItems: 'center', 73 | backgroundColor: '#F5FCFF', 74 | }, 75 | welcome: { 76 | fontSize: 20, 77 | textAlign: 'center', 78 | margin: 10, 79 | }, 80 | instructions: { 81 | textAlign: 'center', 82 | color: '#333333', 83 | marginBottom: 5, 84 | }, 85 | }); 86 | 87 | AppRegistry.registerComponent('testComp', () => testComp); 88 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # react-native-record-audio-ios 2 | 3 | This is a wrapper for react-native that records audio. The options are to start and stop recording. Supported files include .caf, .m4a, and .wav types. This is for ios only. 4 | 5 | # Add it to your project 6 | 7 | npm install react-native-record-audio-ios --save 8 | 9 | In XCode, in the project navigator, right click Libraries ➜ Add Files to [your project's name] 10 | 11 | Go to node_modules ➜ react-native-record-audio-ios and add RNRecordAudio.xcodeproj 12 | 13 | In XCode, in the project navigator, select your project. Add libRNRecordAudio.a to your project's Build Phases ➜ Link Binary With Libraries 14 | 15 | Click RNRecordAudio.xcodeproj in the project navigator and go the Build Settings tab. Make sure 'All' is toggled on (instead of 'Basic'). Look for Header Search Paths and make sure it contains both $(SRCROOT)/../react-native/React and $(SRCROOT)/../../React - mark both as recursive. 16 | 17 | Run your project (Cmd+R) 18 | 19 | Setup trouble? 20 | 21 | If you get stuck, take a look at Brent Vatne's blog. His blog is my go to reference for this stuff. 22 | 23 | # Api Setup 24 | ```javascript 25 | var React = require('react-native'); 26 | 27 | var { NativeModules } = React; 28 | 29 | var { RNRecordAudio } = NativeModules; 30 | 31 | // Start Recording 32 | 33 | RNRecordAudio.startRecord( 34 | "test.m4a", // filename 35 | 36 | function errorCallback(results) { 37 | console.log('JS Error: ' + results['errMsg']); 38 | }, 39 | 40 | function successCallback(results) { 41 | console.log('JS Success: ' + results['successMsg']); 42 | } 43 | ); 44 | 45 | // Stop Recording 46 | 47 | RNRecordAudio.stopRecord( 48 | "test.m4a", // filename 49 | 50 | function errorCallback(results) { 51 | console.log('JS Error: ' + results['errMsg']); 52 | }, 53 | 54 | function successCallback(results) { 55 | console.log('JS Success: ' + results['successMsg']); 56 | } 57 | ); 58 | ``` 59 | 60 | 61 | # Additional Notes 62 | 63 | The recorded audio is saved in the app documents directory. The format/file type of the audio should be either a .caf, .wav, or .m4a. 64 | 65 | # Error Callback 66 | 67 | The following will cause an error callback (use the console.log to see the specific message): 68 | 69 | 1) Filename not included in api call 70 | 71 | 2) Filename is a hidden file 72 | 73 | 3) File is not .caf, .wav, .m4a type 74 | 75 | 4) If stopping, file does not exist in the app documents directory 76 | 77 | 5) If stopping, recording is not already in progress 78 | 79 | # Acknowledgements 80 | 81 | Special thanks to Joshua Sierles for his work and code on react-native-audio. Brent Vatne for his posts on creating a react native packager. Some portions of this code have been based on answers from stackoverflow. This package also owes a special thanks to the tutorial by Jay Garcia at Modus Create on how to create a custom react native module. 82 | --------------------------------------------------------------------------------