├── index.js ├── android ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── sensors │ │ ├── RNSensorsPackage.java │ │ ├── Gyroscope.java │ │ └── Accelerometer.java └── build.gradle ├── package.json ├── ios ├── Gyroscope.h ├── Accelerometer.h ├── Gyroscope.m ├── Accelerometer.m └── RNSensors.xcodeproj │ └── project.pbxproj ├── .gitignore ├── src ├── sensors.js └── decorator.js └── README.md /index.js: -------------------------------------------------------------------------------- 1 | import Sensors from './src/sensors'; 2 | import decorator from './src/decorator'; 3 | 4 | export default { 5 | ...Sensors, 6 | decorator, 7 | }; 8 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-sensors", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "keywords": [ 7 | "react-native" 8 | ], 9 | "author": "", 10 | "license": "", 11 | "peerDependencies": { 12 | "react-native": "^0.40.0" 13 | }, 14 | "dependencies": { 15 | "rxjs": "^5.0.2" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ios/Gyroscope.h: -------------------------------------------------------------------------------- 1 | // Inspired by https://github.com/pwmckenna/react-native-motion-manager 2 | 3 | #import 4 | #import 5 | 6 | @interface Gyroscope : NSObject { 7 | CMMotionManager *_motionManager; 8 | } 9 | 10 | - (void) setUpdateInterval:(double) interval; 11 | - (void) getUpdateInterval:(RCTResponseSenderBlock) cb; 12 | - (void) getData:(RCTResponseSenderBlock) cb; 13 | - (void) startUpdates; 14 | - (void) stopUpdates; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ios/Accelerometer.h: -------------------------------------------------------------------------------- 1 | // Inspired by https://github.com/pwmckenna/react-native-motion-manager 2 | 3 | #import 4 | #import 5 | 6 | @interface Accelerometer : NSObject { 7 | CMMotionManager *_motionManager; 8 | } 9 | 10 | - (void) setUpdateInterval:(double) interval; 11 | - (void) getUpdateInterval:(RCTResponseSenderBlock) cb; 12 | - (void) getData:(RCTResponseSenderBlock) cb; 13 | - (void) startUpdates; 14 | - (void) stopUpdates; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | apply plugin: 'com.android.library' 3 | 4 | android { 5 | compileSdkVersion 23 6 | buildToolsVersion "23.0.1" 7 | 8 | defaultConfig { 9 | minSdkVersion 16 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | ndk { 14 | abiFilters "armeabi-v7a", "x86" 15 | } 16 | } 17 | lintOptions { 18 | warning 'InvalidPackage' 19 | } 20 | } 21 | 22 | dependencies { 23 | compile 'com.facebook.react:react-native:0.20.+' 24 | } 25 | -------------------------------------------------------------------------------- /.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 | # Android/IJ 26 | # 27 | *.iml 28 | .idea 29 | .gradle 30 | local.properties 31 | 32 | # node.js 33 | # 34 | node_modules/ 35 | npm-debug.log 36 | 37 | # BUCK 38 | buck-out/ 39 | \.buckd/ 40 | android/app/libs 41 | android/keystores/debug.keystore 42 | -------------------------------------------------------------------------------- /android/src/main/java/com/sensors/RNSensorsPackage.java: -------------------------------------------------------------------------------- 1 | 2 | package com.sensors; 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 RNSensorsPackage implements ReactPackage { 14 | @Override 15 | public List createNativeModules(ReactApplicationContext reactContext) { 16 | return Arrays.asList(new Gyroscope(reactContext), new Accelerometer(reactContext)); 17 | } 18 | 19 | @Override 20 | public List> createJSModules() { 21 | return Collections.emptyList(); 22 | } 23 | 24 | @Override 25 | public List createViewManagers(ReactApplicationContext reactContext) { 26 | return Collections.emptyList(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/sensors.js: -------------------------------------------------------------------------------- 1 | import { NativeModules, DeviceEventEmitter } from 'react-native'; 2 | import Rx from 'rxjs/Rx'; 3 | const { Gyroscope: GyroNative, Accelerometer: AccNative } = NativeModules; 4 | 5 | const handle = { 6 | Accelerometer: AccNative, 7 | Gyroscope: GyroNative, 8 | }; 9 | 10 | const RNSensors = { 11 | start: function (type, updateInterval) { 12 | const api = handle[type]; 13 | api.setUpdateInterval(updateInterval); 14 | api.startUpdates(); 15 | }, 16 | 17 | stop: function (type) { 18 | const api = handle[type]; 19 | api.stopUpdates(); 20 | }, 21 | }; 22 | 23 | function createSensorMonitorCreator(sensorType) { 24 | function Creator(options = {}) { 25 | const { 26 | updateInterval = 100, // time in ms 27 | } = (options || {}); 28 | let observer; 29 | // Start the sensor manager 30 | RNSensors.start(sensorType, updateInterval); 31 | 32 | // Instanciate observable 33 | const observable = Rx.Observable.create(function (obs) { 34 | observer = obs; 35 | DeviceEventEmitter.addListener(sensorType, function(data) { 36 | observer.next(data); 37 | }); 38 | }) 39 | 40 | // Stop the sensor manager 41 | observable.stop = () => { 42 | RNSensors.stop(sensorType); 43 | observer.complete(); 44 | }; 45 | 46 | return observable; 47 | } 48 | 49 | return Creator; 50 | } 51 | 52 | // TODO: lazily intialize them (maybe via getter) 53 | const Accelerometer = createSensorMonitorCreator('Accelerometer'); 54 | const Gyroscope = createSensorMonitorCreator('Gyroscope'); 55 | const Magnetometer = createSensorMonitorCreator('Magnetometer'); 56 | 57 | export default { 58 | Accelerometer, 59 | Gyroscope, 60 | Magnetometer, 61 | }; 62 | -------------------------------------------------------------------------------- /src/decorator.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Sensors from './sensors'; 3 | 4 | const AVAILABLE_SENSORS = ['Accelerometer', 'Gyroscope']; 5 | const optionsType = React.PropTypes.shape({ 6 | updateInterval: React.PropTypes.number, 7 | }); 8 | 9 | class SensorWrapper extends React.Component { 10 | static propTypes = { 11 | children: React.PropTypes.node.isRequired, 12 | sensors: React.PropTypes.shape({ 13 | Accelerometer: React.PropTypes.oneOfType([ 14 | React.PropTypes.bool, 15 | optionsType, 16 | ]), 17 | Gyroscope: React.PropTypes.oneOfType([ 18 | React.PropTypes.bool, 19 | optionsType, 20 | ]), 21 | Magnetometer: React.PropTypes.oneOfType([ 22 | React.PropTypes.bool, 23 | optionsType, 24 | ]), 25 | }), 26 | } 27 | 28 | constructor(props) { 29 | super(props); 30 | this.state = { 31 | _observables: [], 32 | }; 33 | } 34 | 35 | componentWillMount() { 36 | const observables = []; 37 | Object.entries(this.props.sensors).forEach(([name, sensorOptions]) => { 38 | const options = typeof(sensorOptions) === 'boolean' ? null : sensorOptions; 39 | const observable = new Sensors[name](options); 40 | observables.push(observable); 41 | 42 | observable.subscribe(sensorValue => { 43 | this.setState({ 44 | [name]: sensorValue, 45 | }); 46 | }); 47 | }); 48 | 49 | this.setState({ 50 | _observables: observables, 51 | }); 52 | } 53 | 54 | componentWillUnmount() { 55 | this.state._observables.forEach(observable => observable.stop()); 56 | } 57 | 58 | render() { 59 | return React.cloneElement(this.props.children, this.state); 60 | } 61 | } 62 | 63 | export default function decorator(options = {}) { 64 | const sensors = Object.keys(options) 65 | .filter(key => AVAILABLE_SENSORS.includes(key)) 66 | .filter(key => options[key]) 67 | .reduce((carry, key) => { 68 | carry[key] = options[key]; 69 | return carry 70 | }, {}); 71 | 72 | return Component => props => ( 73 | 74 | 75 | 76 | ) 77 | } 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # react-native-sensors 3 | 4 | ## Getting started 5 | 6 | `$ npm install react-native-sensors --save` 7 | 8 | ### Mostly automatic installation 9 | 10 | `$ react-native link react-native-sensors` 11 | 12 | ### Manual installation 13 | 14 | #### iOS 15 | 16 | 1. In XCode, in the project navigator, right click `Libraries` ➜ `Add Files to [your project's name]` 17 | 2. Go to `node_modules` ➜ `react-native-sensors` and add `RNSensors.xcodeproj` 18 | 3. In XCode, in the project navigator, select your project. Add `libRNSensors.a` to your project's `Build Phases` ➜ `Link Binary With Libraries` 19 | 4. Run your project (`Cmd+R`)< 20 | 21 | #### Android 22 | 23 | 1. Open up `android/app/src/main/java/[...]/MainActivity.java` 24 | - Add `import com.reactlibrary.RNSensorsPackage;` to the imports at the top of the file 25 | - Add `new RNSensorsPackage()` to the list returned by the `getPackages()` method 26 | 2. Append the following lines to `android/settings.gradle`: 27 | ``` 28 | include ':react-native-sensors' 29 | project(':react-native-sensors').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sensors/android') 30 | ``` 31 | 3. Insert the following lines inside the dependencies block in `android/app/build.gradle`: 32 | ``` 33 | compile project(':react-native-sensors') 34 | ``` 35 | 36 | ## Usage 37 | 38 | ### Sensor API 39 | 40 | ```javascript 41 | import { Accelerometer, Gyroscope } from 'react-native-sensors'; 42 | const accelerationObservable = new Accelerometer({ 43 | updateInterval: 100, // defaults to 100ms 44 | }); 45 | 46 | // Normal RxJS functions 47 | accelerationObservable 48 | .map(({ x, y, z }) => x + y + z) 49 | .filter(speed => speed > 20) 50 | .subscribe(speed => console.log(`You moved your phone with ${speed}`)); 51 | 52 | setTimeout(() => { 53 | accelerationObservable.stop(); 54 | }, 1000); 55 | ``` 56 | 57 | ### Decorator usage 58 | 59 | ```javascript 60 | import React, { Component } from 'react'; 61 | import { Text, View } from 'react-native'; 62 | import { decorator as sensors } from 'react-native-sensors'; 63 | 64 | class MyComponent { // no lifecycle needed 65 | render() { 66 | const { 67 | Accelerometer, 68 | Gyroscope, 69 | } = this.props; 70 | 71 | return ( 72 | 73 | 74 | Acceleration has value: {Accelerometer} 75 | Gyro has value: {Gyroscope} 76 | 77 | 78 | ); 79 | } 80 | } 81 | 82 | export default sensors({ 83 | Accelerometer: { 84 | updateInterval: 300, // optional 85 | }, 86 | Gyroscope: true, 87 | Magnetometer: false, // disabled 88 | })(MyComponent); 89 | ``` 90 | 91 | ## Credits 92 | 93 | This project is inspired by the [react-native-sensor-manager](https://github.com/kprimice/react-native-sensor-manager) and by the [react-native-motion-manager](https://github.com/pwmckenna/react-native-motion-manager). Both have similar solutions with a non-uniform interface and this project aims to unify both. 94 | -------------------------------------------------------------------------------- /android/src/main/java/com/sensors/Gyroscope.java: -------------------------------------------------------------------------------- 1 | package com.sensors; 2 | 3 | import android.os.Bundle; 4 | import android.hardware.Sensor; 5 | import android.hardware.SensorEvent; 6 | import android.hardware.SensorEventListener; 7 | import android.hardware.SensorManager; 8 | import android.util.Log; 9 | import android.support.annotation.Nullable; 10 | 11 | import com.facebook.react.bridge.Arguments; 12 | import com.facebook.react.bridge.ReactApplicationContext; 13 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 14 | import com.facebook.react.bridge.ReactMethod; 15 | import com.facebook.react.bridge.WritableMap; 16 | import com.facebook.react.bridge.Callback; 17 | import com.facebook.react.modules.core.DeviceEventManagerModule; 18 | 19 | public class Gyroscope extends ReactContextBaseJavaModule implements SensorEventListener { 20 | 21 | private final ReactApplicationContext reactContext; 22 | private final SensorManager sensorManager; 23 | private final Sensor sensor; 24 | private int interval; 25 | private Arguments arguments; 26 | 27 | public Gyroscope(ReactApplicationContext reactContext) { 28 | super(reactContext); 29 | this.reactContext = reactContext; 30 | this.sensorManager = (SensorManager)reactContext.getSystemService(reactContext.SENSOR_SERVICE); 31 | this.sensor = this.sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); 32 | 33 | if (this.sensor == null) { 34 | // No sensor found, throw error 35 | throw new RuntimeException("No Gyroscope found"); 36 | } 37 | } 38 | 39 | // RN Methods 40 | @ReactMethod 41 | public void setUpdateInterval(int newInterval) { 42 | this.interval = newInterval; 43 | } 44 | 45 | @ReactMethod 46 | public void startUpdates() { 47 | // Milisecond to Mikrosecond conversion 48 | sensorManager.registerListener(this, sensor, this.interval * 1000); 49 | } 50 | 51 | @ReactMethod 52 | public void stopUpdates() { 53 | sensorManager.unregisterListener(this); 54 | } 55 | 56 | @Override 57 | public String getName() { 58 | return "Gyroscope"; 59 | } 60 | 61 | // SensorEventListener Interface 62 | private void sendEvent(String eventName, @Nullable WritableMap params) { 63 | try { 64 | this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) 65 | .emit(eventName, params); 66 | } catch (RuntimeException e) { 67 | Log.e("ERROR", "java.lang.RuntimeException: Trying to invoke Javascript before CatalystInstance has been set!"); 68 | } 69 | } 70 | 71 | @Override 72 | public void onSensorChanged(SensorEvent sensorEvent) { 73 | Sensor mySensor = sensorEvent.sensor; 74 | WritableMap map = arguments.createMap(); 75 | 76 | if (mySensor.getType() == Sensor.TYPE_GYROSCOPE) { 77 | map.putDouble("x", sensorEvent.values[0]); 78 | map.putDouble("y", sensorEvent.values[1]); 79 | map.putDouble("z", sensorEvent.values[2]); 80 | map.putDouble("timestamp", (double) System.currentTimeMillis()); 81 | sendEvent("Gyroscope", map); 82 | } 83 | } 84 | 85 | @Override 86 | public void onAccuracyChanged(Sensor sensor, int accuracy) { 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /android/src/main/java/com/sensors/Accelerometer.java: -------------------------------------------------------------------------------- 1 | package com.sensors; 2 | 3 | import android.os.Bundle; 4 | import android.hardware.Sensor; 5 | import android.hardware.SensorEvent; 6 | import android.hardware.SensorEventListener; 7 | import android.hardware.SensorManager; 8 | import android.util.Log; 9 | import android.support.annotation.Nullable; 10 | 11 | import com.facebook.react.bridge.Arguments; 12 | import com.facebook.react.bridge.ReactApplicationContext; 13 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 14 | import com.facebook.react.bridge.ReactMethod; 15 | import com.facebook.react.bridge.WritableMap; 16 | import com.facebook.react.bridge.Callback; 17 | import com.facebook.react.modules.core.DeviceEventManagerModule; 18 | 19 | public class Accelerometer extends ReactContextBaseJavaModule implements SensorEventListener { 20 | 21 | private final ReactApplicationContext reactContext; 22 | private final SensorManager sensorManager; 23 | private final Sensor sensor; 24 | private int interval; 25 | private Arguments arguments; 26 | 27 | public Accelerometer(ReactApplicationContext reactContext) { 28 | super(reactContext); 29 | this.reactContext = reactContext; 30 | this.sensorManager = (SensorManager)reactContext.getSystemService(reactContext.SENSOR_SERVICE); 31 | this.sensor = this.sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 32 | 33 | if (this.sensor == null) { 34 | // No sensor found, throw error 35 | throw new RuntimeException("No Accelerometer found"); 36 | } 37 | } 38 | 39 | // RN Methods 40 | @ReactMethod 41 | public void setUpdateInterval(int newInterval) { 42 | this.interval = newInterval; 43 | } 44 | 45 | @ReactMethod 46 | public void startUpdates() { 47 | // Milisecond to Mikrosecond conversion 48 | sensorManager.registerListener(this, sensor, this.interval * 1000); 49 | } 50 | 51 | @ReactMethod 52 | public void stopUpdates() { 53 | sensorManager.unregisterListener(this); 54 | } 55 | 56 | @Override 57 | public String getName() { 58 | return "Accelerometer"; 59 | } 60 | 61 | // SensorEventListener Interface 62 | private void sendEvent(String eventName, @Nullable WritableMap params) { 63 | try { 64 | this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) 65 | .emit(eventName, params); 66 | } catch (RuntimeException e) { 67 | Log.e("ERROR", "java.lang.RuntimeException: Trying to invoke Javascript before CatalystInstance has been set!"); 68 | } 69 | } 70 | 71 | @Override 72 | public void onSensorChanged(SensorEvent sensorEvent) { 73 | Sensor mySensor = sensorEvent.sensor; 74 | WritableMap map = arguments.createMap(); 75 | 76 | if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) { 77 | map.putDouble("x", sensorEvent.values[0]); 78 | map.putDouble("y", sensorEvent.values[1]); 79 | map.putDouble("z", sensorEvent.values[2]); 80 | map.putDouble("timestamp", (double) System.currentTimeMillis()); 81 | sendEvent("Accelerometer", map); 82 | } 83 | } 84 | 85 | @Override 86 | public void onAccuracyChanged(Sensor sensor, int accuracy) { 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /ios/Gyroscope.m: -------------------------------------------------------------------------------- 1 | // Inspired by https://github.com/pwmckenna/react-native-motion-manager 2 | 3 | #import "Gyroscope.h" 4 | #import 5 | #import 6 | 7 | @implementation Gyroscope 8 | 9 | @synthesize bridge = _bridge; 10 | RCT_EXPORT_MODULE(); 11 | 12 | - (id) init { 13 | self = [super init]; 14 | NSLog(@"Gyroscope"); 15 | 16 | if (self) { 17 | self->_motionManager = [[CMMotionManager alloc] init]; 18 | //Gyroscope 19 | if([self->_motionManager isGyroAvailable]) 20 | { 21 | NSLog(@"Gyroscope available"); 22 | /* Start the gyroscope if it is not active already */ 23 | if([self->_motionManager isGyroActive] == NO) 24 | { 25 | NSLog(@"Gyroscope active"); 26 | } else { 27 | NSLog(@"Gyroscope not active"); 28 | } 29 | } 30 | else 31 | { 32 | NSLog(@"Gyroscope not Available!"); 33 | } 34 | } 35 | return self; 36 | } 37 | 38 | RCT_EXPORT_METHOD(setUpdateInterval:(double) interval) { 39 | NSLog(@"setGyroUpdateInterval: %f", interval); 40 | double intervalInSeconds = interval * 1000; 41 | 42 | [self->_motionManager setGyroUpdateInterval:intervalInSeconds]; 43 | } 44 | 45 | RCT_EXPORT_METHOD(getUpdateInterval:(RCTResponseSenderBlock) cb) { 46 | double interval = self->_motionManager.gyroUpdateInterval; 47 | NSLog(@"getUpdateInterval: %f", interval); 48 | cb(@[[NSNull null], [NSNumber numberWithDouble:interval]]); 49 | } 50 | 51 | RCT_EXPORT_METHOD(getData:(RCTResponseSenderBlock) cb) { 52 | double x = self->_motionManager.gyroData.rotationRate.x; 53 | double y = self->_motionManager.gyroData.rotationRate.y; 54 | double z = self->_motionManager.gyroData.rotationRate.z; 55 | double timestamp = self->_motionManager.gyroData.timestamp; 56 | 57 | NSLog(@"getData: %f, %f, %f, %f", x, y, z, timestamp); 58 | 59 | cb(@[[NSNull null], @{ 60 | @"x" : [NSNumber numberWithDouble:x], 61 | @"y" : [NSNumber numberWithDouble:y], 62 | @"z" : [NSNumber numberWithDouble:z], 63 | @"timestamp" : [NSNumber numberWithDouble:timestamp] 64 | }] 65 | ); 66 | } 67 | 68 | RCT_EXPORT_METHOD(startUpdates) { 69 | NSLog(@"startUpdates"); 70 | [self->_motionManager startGyroUpdates]; 71 | 72 | /* Receive the gyroscope data on this block */ 73 | [self->_motionManager startGyroUpdatesToQueue:[NSOperationQueue mainQueue] 74 | withHandler:^(CMGyroData *gyroData, NSError *error) 75 | { 76 | double x = gyroData.rotationRate.x; 77 | double y = gyroData.rotationRate.y; 78 | double z = gyroData.rotationRate.z; 79 | double timestamp = gyroData.timestamp; 80 | NSLog(@"startUpdates: %f, %f, %f, %f", x, y, z, timestamp); 81 | 82 | [self.bridge.eventDispatcher sendDeviceEventWithName:@"Gyroscope" body:@{ 83 | @"x" : [NSNumber numberWithDouble:x], 84 | @"y" : [NSNumber numberWithDouble:y], 85 | @"z" : [NSNumber numberWithDouble:z], 86 | @"timestamp" : [NSNumber numberWithDouble:timestamp] 87 | }]; 88 | }]; 89 | 90 | } 91 | 92 | RCT_EXPORT_METHOD(stopUpdates) { 93 | NSLog(@"stopUpdates"); 94 | [self->_motionManager stopGyroUpdates]; 95 | } 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /ios/Accelerometer.m: -------------------------------------------------------------------------------- 1 | 2 | // Accelerometer.m 3 | 4 | 5 | #import 6 | #import 7 | #import "Accelerometer.h" 8 | 9 | @implementation Accelerometer 10 | 11 | @synthesize bridge = _bridge; 12 | 13 | RCT_EXPORT_MODULE(); 14 | 15 | - (id) init { 16 | self = [super init]; 17 | NSLog(@"Accelerometer"); 18 | 19 | if (self) { 20 | self->_motionManager = [[CMMotionManager alloc] init]; 21 | //Accelerometer 22 | if([self->_motionManager isAccelerometerAvailable]) 23 | { 24 | NSLog(@"Accelerometer available"); 25 | /* Start the accelerometer if it is not active already */ 26 | if([self->_motionManager isAccelerometerActive] == NO) 27 | { 28 | NSLog(@"Accelerometer active"); 29 | } else { 30 | NSLog(@"Accelerometer not active"); 31 | } 32 | } 33 | else 34 | { 35 | NSLog(@"Accelerometer not available!"); 36 | } 37 | } 38 | return self; 39 | } 40 | 41 | RCT_EXPORT_METHOD(setUpdateInterval:(double) interval) { 42 | NSLog(@"setUpdateInterval: %f", interval); 43 | double intervalInSeconds = interval * 1000; 44 | 45 | [self->_motionManager setAccelerometerUpdateInterval:intervalInSeconds]; 46 | } 47 | 48 | RCT_EXPORT_METHOD(getUpdateInterval:(RCTResponseSenderBlock) cb) { 49 | double interval = self->_motionManager.accelerometerUpdateInterval; 50 | NSLog(@"getUpdateInterval: %f", interval); 51 | cb(@[[NSNull null], [NSNumber numberWithDouble:interval]]); 52 | } 53 | 54 | RCT_EXPORT_METHOD(getData:(RCTResponseSenderBlock) cb) { 55 | double x = self->_motionManager.accelerometerData.acceleration.x; 56 | double y = self->_motionManager.accelerometerData.acceleration.y; 57 | double z = self->_motionManager.accelerometerData.acceleration.z; 58 | double timestamp = self->_motionManager.accelerometerData.timestamp; 59 | 60 | NSLog(@"getData: %f, %f, %f, %f", x, y, z, timestamp); 61 | 62 | cb(@[[NSNull null], @{ 63 | @"x" : [NSNumber numberWithDouble:x], 64 | @"y" : [NSNumber numberWithDouble:y], 65 | @"z" : [NSNumber numberWithDouble:z], 66 | @"timestamp" : [NSNumber numberWithDouble:timestamp] 67 | }] 68 | ); 69 | } 70 | 71 | RCT_EXPORT_METHOD(startUpdates) { 72 | NSLog(@"startUpdates"); 73 | [self->_motionManager startAccelerometerUpdates]; 74 | 75 | /* Receive the ccelerometer data on this block */ 76 | [self->_motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue] 77 | withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) 78 | { 79 | double x = accelerometerData.acceleration.x; 80 | double y = accelerometerData.acceleration.y; 81 | double z = accelerometerData.acceleration.z; 82 | double timestamp = accelerometerData.timestamp; 83 | NSLog(@"startAccelerometerUpdates: %f, %f, %f, %f", x, y, z, timestamp); 84 | 85 | [self.bridge.eventDispatcher sendDeviceEventWithName:@"Accelerometer" body:@{ 86 | @"x" : [NSNumber numberWithDouble:x], 87 | @"y" : [NSNumber numberWithDouble:y], 88 | @"z" : [NSNumber numberWithDouble:z], 89 | @"timestamp" : [NSNumber numberWithDouble:timestamp] 90 | }]; 91 | }]; 92 | 93 | } 94 | 95 | RCT_EXPORT_METHOD(stopUpdates) { 96 | NSLog(@"stopUpdates"); 97 | [self->_motionManager stopAccelerometerUpdates]; 98 | } 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /ios/RNSensors.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E7FCE1881E14639E005C5155 /* Gyroscope.m in Sources */ = {isa = PBXBuildFile; fileRef = E7FCE1871E14639E005C5155 /* Gyroscope.m */; }; 11 | E7FCE18B1E150266005C5155 /* Accelerometer.m in Sources */ = {isa = PBXBuildFile; fileRef = E7FCE18A1E150266005C5155 /* Accelerometer.m */; }; 12 | /* End PBXBuildFile section */ 13 | 14 | /* Begin PBXCopyFilesBuildPhase section */ 15 | 58B511D91A9E6C8500147676 /* CopyFiles */ = { 16 | isa = PBXCopyFilesBuildPhase; 17 | buildActionMask = 2147483647; 18 | dstPath = "include/$(PRODUCT_NAME)"; 19 | dstSubfolderSpec = 16; 20 | files = ( 21 | ); 22 | runOnlyForDeploymentPostprocessing = 0; 23 | }; 24 | /* End PBXCopyFilesBuildPhase section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | 134814201AA4EA6300B7C361 /* libRNSensors.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNSensors.a; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | E7FCE1861E14639E005C5155 /* Gyroscope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Gyroscope.h; sourceTree = ""; }; 29 | E7FCE1871E14639E005C5155 /* Gyroscope.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Gyroscope.m; sourceTree = ""; }; 30 | E7FCE1891E150266005C5155 /* Accelerometer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Accelerometer.h; sourceTree = ""; }; 31 | E7FCE18A1E150266005C5155 /* Accelerometer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Accelerometer.m; sourceTree = ""; }; 32 | /* End PBXFileReference section */ 33 | 34 | /* Begin PBXFrameworksBuildPhase section */ 35 | 58B511D81A9E6C8500147676 /* Frameworks */ = { 36 | isa = PBXFrameworksBuildPhase; 37 | buildActionMask = 2147483647; 38 | files = ( 39 | ); 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | /* End PBXFrameworksBuildPhase section */ 43 | 44 | /* Begin PBXGroup section */ 45 | 134814211AA4EA7D00B7C361 /* Products */ = { 46 | isa = PBXGroup; 47 | children = ( 48 | 134814201AA4EA6300B7C361 /* libRNSensors.a */, 49 | ); 50 | name = Products; 51 | sourceTree = ""; 52 | }; 53 | 58B511D21A9E6C8500147676 = { 54 | isa = PBXGroup; 55 | children = ( 56 | E7FCE1891E150266005C5155 /* Accelerometer.h */, 57 | E7FCE18A1E150266005C5155 /* Accelerometer.m */, 58 | E7FCE1861E14639E005C5155 /* Gyroscope.h */, 59 | E7FCE1871E14639E005C5155 /* Gyroscope.m */, 60 | 134814211AA4EA7D00B7C361 /* Products */, 61 | ); 62 | sourceTree = ""; 63 | }; 64 | /* End PBXGroup section */ 65 | 66 | /* Begin PBXNativeTarget section */ 67 | 58B511DA1A9E6C8500147676 /* RNSensors */ = { 68 | isa = PBXNativeTarget; 69 | buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNSensors" */; 70 | buildPhases = ( 71 | 58B511D71A9E6C8500147676 /* Sources */, 72 | 58B511D81A9E6C8500147676 /* Frameworks */, 73 | 58B511D91A9E6C8500147676 /* CopyFiles */, 74 | ); 75 | buildRules = ( 76 | ); 77 | dependencies = ( 78 | ); 79 | name = RNSensors; 80 | productName = RCTDataManager; 81 | productReference = 134814201AA4EA6300B7C361 /* libRNSensors.a */; 82 | productType = "com.apple.product-type.library.static"; 83 | }; 84 | /* End PBXNativeTarget section */ 85 | 86 | /* Begin PBXProject section */ 87 | 58B511D31A9E6C8500147676 /* Project object */ = { 88 | isa = PBXProject; 89 | attributes = { 90 | LastUpgradeCheck = 0610; 91 | ORGANIZATIONNAME = Facebook; 92 | TargetAttributes = { 93 | 58B511DA1A9E6C8500147676 = { 94 | CreatedOnToolsVersion = 6.1.1; 95 | }; 96 | }; 97 | }; 98 | buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNSensors" */; 99 | compatibilityVersion = "Xcode 3.2"; 100 | developmentRegion = English; 101 | hasScannedForEncodings = 0; 102 | knownRegions = ( 103 | en, 104 | ); 105 | mainGroup = 58B511D21A9E6C8500147676; 106 | productRefGroup = 58B511D21A9E6C8500147676; 107 | projectDirPath = ""; 108 | projectRoot = ""; 109 | targets = ( 110 | 58B511DA1A9E6C8500147676 /* RNSensors */, 111 | ); 112 | }; 113 | /* End PBXProject section */ 114 | 115 | /* Begin PBXSourcesBuildPhase section */ 116 | 58B511D71A9E6C8500147676 /* Sources */ = { 117 | isa = PBXSourcesBuildPhase; 118 | buildActionMask = 2147483647; 119 | files = ( 120 | E7FCE1881E14639E005C5155 /* Gyroscope.m in Sources */, 121 | E7FCE18B1E150266005C5155 /* Accelerometer.m in Sources */, 122 | ); 123 | runOnlyForDeploymentPostprocessing = 0; 124 | }; 125 | /* End PBXSourcesBuildPhase section */ 126 | 127 | /* Begin XCBuildConfiguration section */ 128 | 58B511ED1A9E6C8500147676 /* Debug */ = { 129 | isa = XCBuildConfiguration; 130 | buildSettings = { 131 | ALWAYS_SEARCH_USER_PATHS = NO; 132 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 133 | CLANG_CXX_LIBRARY = "libc++"; 134 | CLANG_ENABLE_MODULES = YES; 135 | CLANG_ENABLE_OBJC_ARC = YES; 136 | CLANG_WARN_BOOL_CONVERSION = YES; 137 | CLANG_WARN_CONSTANT_CONVERSION = YES; 138 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 139 | CLANG_WARN_EMPTY_BODY = YES; 140 | CLANG_WARN_ENUM_CONVERSION = YES; 141 | CLANG_WARN_INT_CONVERSION = YES; 142 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 143 | CLANG_WARN_UNREACHABLE_CODE = YES; 144 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 145 | COPY_PHASE_STRIP = NO; 146 | ENABLE_STRICT_OBJC_MSGSEND = YES; 147 | GCC_C_LANGUAGE_STANDARD = gnu99; 148 | GCC_DYNAMIC_NO_PIC = NO; 149 | GCC_OPTIMIZATION_LEVEL = 0; 150 | GCC_PREPROCESSOR_DEFINITIONS = ( 151 | "DEBUG=1", 152 | "$(inherited)", 153 | ); 154 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 155 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 156 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 157 | GCC_WARN_UNDECLARED_SELECTOR = YES; 158 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 159 | GCC_WARN_UNUSED_FUNCTION = YES; 160 | GCC_WARN_UNUSED_VARIABLE = YES; 161 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 162 | MTL_ENABLE_DEBUG_INFO = YES; 163 | ONLY_ACTIVE_ARCH = YES; 164 | SDKROOT = iphoneos; 165 | }; 166 | name = Debug; 167 | }; 168 | 58B511EE1A9E6C8500147676 /* Release */ = { 169 | isa = XCBuildConfiguration; 170 | buildSettings = { 171 | ALWAYS_SEARCH_USER_PATHS = NO; 172 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 173 | CLANG_CXX_LIBRARY = "libc++"; 174 | CLANG_ENABLE_MODULES = YES; 175 | CLANG_ENABLE_OBJC_ARC = YES; 176 | CLANG_WARN_BOOL_CONVERSION = YES; 177 | CLANG_WARN_CONSTANT_CONVERSION = YES; 178 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 179 | CLANG_WARN_EMPTY_BODY = YES; 180 | CLANG_WARN_ENUM_CONVERSION = YES; 181 | CLANG_WARN_INT_CONVERSION = YES; 182 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 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_WARN_64_TO_32_BIT_CONVERSION = YES; 190 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 191 | GCC_WARN_UNDECLARED_SELECTOR = YES; 192 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 193 | GCC_WARN_UNUSED_FUNCTION = YES; 194 | GCC_WARN_UNUSED_VARIABLE = YES; 195 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 196 | MTL_ENABLE_DEBUG_INFO = NO; 197 | SDKROOT = iphoneos; 198 | VALIDATE_PRODUCT = YES; 199 | }; 200 | name = Release; 201 | }; 202 | 58B511F01A9E6C8500147676 /* Debug */ = { 203 | isa = XCBuildConfiguration; 204 | buildSettings = { 205 | HEADER_SEARCH_PATHS = ( 206 | "$(inherited)", 207 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 208 | ); 209 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 210 | OTHER_LDFLAGS = "-ObjC"; 211 | PRODUCT_NAME = RNSensors; 212 | SKIP_INSTALL = YES; 213 | }; 214 | name = Debug; 215 | }; 216 | 58B511F11A9E6C8500147676 /* Release */ = { 217 | isa = XCBuildConfiguration; 218 | buildSettings = { 219 | HEADER_SEARCH_PATHS = ( 220 | "$(inherited)", 221 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 222 | ); 223 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 224 | OTHER_LDFLAGS = "-ObjC"; 225 | PRODUCT_NAME = RNSensors; 226 | SKIP_INSTALL = YES; 227 | }; 228 | name = Release; 229 | }; 230 | /* End XCBuildConfiguration section */ 231 | 232 | /* Begin XCConfigurationList section */ 233 | 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNSensors" */ = { 234 | isa = XCConfigurationList; 235 | buildConfigurations = ( 236 | 58B511ED1A9E6C8500147676 /* Debug */, 237 | 58B511EE1A9E6C8500147676 /* Release */, 238 | ); 239 | defaultConfigurationIsVisible = 0; 240 | defaultConfigurationName = Release; 241 | }; 242 | 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNSensors" */ = { 243 | isa = XCConfigurationList; 244 | buildConfigurations = ( 245 | 58B511F01A9E6C8500147676 /* Debug */, 246 | 58B511F11A9E6C8500147676 /* Release */, 247 | ); 248 | defaultConfigurationIsVisible = 0; 249 | defaultConfigurationName = Release; 250 | }; 251 | /* End XCConfigurationList section */ 252 | }; 253 | rootObject = 58B511D31A9E6C8500147676 /* Project object */; 254 | } 255 | --------------------------------------------------------------------------------