ä»æ¥ãããã°ã©ããŒã®èŒªã®äžã§ãã»ãšãã©èª°ããFacebookã©ã€ãã©ãª-Reactã«ã€ããŠç¥ã£ãŠããŸãã
Reactã¯ã³ã³ããŒãã³ãã«åºã¥ããŠããŸãã ãããã¯ãã©ãŠã¶ã®DOMèŠçŽ ã«äŒŒãŠãããHTMLã§ã¯ãªãJavaScriptã䜿çšããŠèšè¿°ãããŠããŸãã Facebookã«ãããšãã³ã³ããŒãã³ãã䜿çšãããšãã€ã³ã¿ãŒãã§ãŒã¹ã1åäœæããŠãã¹ãŠã®ããã€ã¹ã«è¡šç€ºã§ããŸãã ãã©ãŠã¶ã§ã¯ãã¹ãŠãæ確ã«ãªã£ãŠããŸãïŒãããã®ã³ã³ããŒãã³ãã¯DOMèŠçŽ ã«å€æãããŸãïŒããã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã«ã€ããŠã¯ã©ãã§ããããã ããã§ãäºæž¬å¯èœã§ããReactã³ã³ããŒãã³ãã¯ãã€ãã£ãã³ã³ããŒãã³ãã«å€æãããŸãã
ãã®èšäºã§ã¯ãç°¡åãªæ©æ°èšã¢ããªã±ãŒã·ã§ã³ã®éçºæ¹æ³ã説æããŸãã ãã€ã©ã€ãã瀺ãã³ãŒãã衚瀺ãããŸãã ãããžã§ã¯ãå
šäœã¯GitHubãžã®ãªã³ã¯ããå
¥æã§ããŸã ã
ããã§ã¯å§ããŸãããã
å¿
èŠæ¡ä»¶
iOSéçºã«ã¯ãXcodeã䜿çšããOS Xãå¿
èŠã§ãã Androidã䜿çšãããšããã¹ãŠãã·ã³ãã«ã«ãªããŸããLinuxãOS XãWindowsããéžæã§ããŸãã ãŸããAndroid SDKãã€ã³ã¹ããŒã«ããå¿
èŠããããŸãã æŠéãã¹ãã«ã¯ãiPhoneãšLollipopãæèŒããAndroidã¹ããŒããã©ã³ãå¿
èŠã§ãã
ãããžã§ã¯ãæ§é ã®äœæ
æåã«ããããžã§ã¯ãæ§é ãäœæããŸãã ã¢ããªã±ãŒã·ã§ã³å
ã®ããŒã¿ãæäœããããã«ããã©ãã¯ã¹ã®èãæ¹ãã€ãŸãå®è£
ãšããŠReduxã䜿çšããŸãã ã«ãŒã¿ãŒãå¿
èŠã§ãã ããã«ReduxããµããŒããããããreact-native-router-fluxãã«ãŒã¿ãŒãšããŠéžæããŸããã
Reduxã«ã€ããŠäžèšã Reduxã¯ãã¢ããªã±ãŒã·ã§ã³ã®ç¶æ
ãä¿åããã·ã³ãã«ãªã©ã€ãã©ãªã§ãã ã¬ã³ããªã³ã°ã¬ã³ããªã³ã°ãªã©ãç¶æ
ã®å€åã«ã€ãã³ããã³ãã©ãŒãã¢ã¿ããã§ããŸãã ãããªãã¥ãŒããªã¢ã«ã§reduxãç解ããããšããå§ãããŸãã
å®è£
ã«åãââããããŸãããã npmã䜿çšããŠreact-native-cliãã€ã³ã¹ããŒã«ããŸããnpmã䜿çšããŠããããžã§ã¯ãã§ã®ãã¹ãŠã®æäœãåŒãç¶ãå®è¡ããŸãã
npm install -g react-native-cli
次ã«ããããžã§ã¯ããäœæããŸãã
react-native init AwesomeProject
äŸåé¢ä¿ãã€ã³ã¹ããŒã«ããŸãã
npm install
ãã®çµæãiosããã³androidãã©ã«ããŒã¯ãããžã§ã¯ãã®ã«ãŒãã«äœæãããããããã®ãã©ãããã©ãŒã ã«ããã€ãã£ãããã¡ã€ã«ããããŸãã index.ios.jsããã³index.android.jsãã¡ã€ã«ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ãšã³ããªãã€ã³ãã§ãã
å¿
èŠãªã©ã€ãã©ãªãã€ã³ã¹ããŒã«ããŸãã
npm install âsave react-native-router-flux redux redux-thunk react-redux lodash
ãã£ã¬ã¯ããªæ§é ãäœæããŸãã
app/ actions/ components/ containers/ constants/ reducers/ services/
ã¢ã¯ã·ã§ã³ãã©ã«ããŒã«ã¯ãã¹ãã¢å
ã®ããŒã¿ã«äœãèµ·ããããèšè¿°ããé¢æ°ãå«ãŸããŸãã
ååã«åºã¥ããã³ã³ããŒãã³ãã«ã¯ãåã
ã®ã€ã³ã¿ãŒãã§ãŒã¹èŠçŽ ã®ã³ã³ããŒãã³ããå«ãŸããŸãã
ã³ã³ããã«ã¯ãã¢ããªã±ãŒã·ã§ã³ã®åããŒãžã®ã«ãŒãã³ã³ããŒãã³ããå«ãŸããŸãã
å®æ°-ååã¯ããèªèº«ãè¡šããŠããŸãã
æžéæ©ã«ã¯ããããããæžéæ©ãããããŸãã ãããã¯ãåä¿¡ããããŒã¿ã«å¿ããŠã¢ããªã±ãŒã·ã§ã³ã®ç¶æ
ãå€æŽããé¢æ°ã§ãã
app / containersãã©ã«ããŒã«app.jsãäœæããŸãã ã¢ããªã±ãŒã·ã§ã³ã®ã«ãŒãèŠçŽ ã¯reduxã©ãããŒã§ãã ãã¹ãŠã®ã«ãŒãã¯éåžžã®ã³ã³ããŒãã³ããšããŠç»é²ãããŸãã åæããããã£ã¯ãã¢ããªã±ãŒã·ã§ã³ã®åæåæã«æ©èœããã«ãŒããã«ãŒã¿ãŒã«æ瀺ããŸãã ã«ãŒãã®ã³ã³ããŒãã³ãããããã£ã§ã¯ãã«ãŒãã«åãæ¿ãããšãã«è¡šç€ºãããã³ã³ããŒãã³ããæž¡ããŸãã
app/containers/app.js <Provider store={store}> <Router hideNavBar={true}> <Route name="launch" component={Launch} initial={true} wrapRouter={true} title="Launch"/> <Route name="counter" component={CounterApp} title="Counter App"/> </Router> </Provider>
app / containerãã£ã¬ã¯ããªã§ãlaunch.jsãäœæããŸãã launch.js-ã«ãŠã³ã¿ãŒããŒãžã«ç§»åããããã®ãã¿ã³ãæã€éåžžã®ã³ã³ããŒãã³ãã
app/containers/launch.js import { Actions } from 'react-native-router-flux'; ⊠<TouchableOpacity onPress={Actions.counter}> <Text>Counter</Text> </TouchableOpacity>
ã¢ã¯ã·ã§ã³-åã«ãŒãã«ã¡ãœããããããªããžã§ã¯ãã ãã®ãããªã¡ãœããã®ååã¯ãã«ãŒãã®nameããããã£ããååŸãããŸãã
ãã¡ã€ã«app / constants / actionTypes.jsã§ãå¯èœãªã«ãŠã³ã¿ãŒã€ãã³ãã«ã€ããŠèª¬æããŸãã
export const INCREMENT = 'INCREMENT'; export const DECREMENT = 'DECREMENT';
app / actionsãã©ã«ããŒã§ãå
容ãå«ãcounterActions.jsãã¡ã€ã«ãäœæããŸãã
app/actions/counterActions.js import * as types from '../constants/actionTypes'; export function increment() { return { type: types.INCREMENT }; } export function decrement() { return { type: types.DECREMENT }; }
å¢åããã³æžåé¢æ°ã¯ãã¬ãã¥ãŒãµãŒã«äœãèµ·ããããèšè¿°ããŸãã ã¢ã¯ã·ã§ã³ã«å¿ããŠããªãã¥ãŒãµãŒã¯ã¢ããªã±ãŒã·ã§ã³ã®ç¶æ
ãå€æŽããŸãã initialState-ãªããžããªã®åæç¶æ
ã説æããŸãã ã¢ããªã±ãŒã·ã§ã³ãåæåããããšãã«ãŠã³ã¿ãŒã¯0ã«èšå®ãããŸãã
app/reducers/counter.js import * as types from '../constants/actionTypes'; const initialState = { count: 0 }; export default function counter(state = initialState, action = {}) { switch (action.type) { case types.INCREMENT: return { ...state, count: state.count + 1 }; case types.DECREMENT: return { ...state, count: state.count - 1 }; default: return state; } }
counter.jsãã¡ã€ã«ã«ã¯ãã«ãŠã³ã¿ãŒå€ãå¢æžããããã®2ã€ã®ãã¿ã³ãå«ãŸããŠãããçŸåšã®å€ã衚瀺ãããŸãã
app/components/counter.js const { counter, increment, decrement } = this.props; ⊠<Text>{counter}</Text> <TouchableOpacity onPress={increment} style={styles.button}> <Text>up</Text> </TouchableOpacity> <TouchableOpacity onPress={decrement} style={styles.button}> <Text>down</Text> </TouchableOpacity>
ã€ãã³ããã³ãã©ãšã«ãŠã³ã¿å€èªäœã¯ãã³ã³ããã³ã³ããŒãã³ãããæž¡ãããŸãã 以äžãæ€èšããŠãã ããã
app/containers/counterApp.js import React, { Component } from 'react-native'; import {bindActionCreators} from 'redux'; import Counter from '../components/counter'; import * as counterActions from '../actions/counterActions'; import { connect } from 'react-redux'; class CounterApp extends Component { constructor(props) { super(props); } render() { const { state, actions } = this.props; return ( <Counter counter={state.count} {...actions} /> ); } } /* . props.state */ export default connect(state => ({ state: state.counter }), /* . props.actions.increment() props.actions.decrement() */ (dispatch) => ({ actions: bindActionCreators(counterActions, dispatch) }) )(CounterApp);
ãã®çµæãå¿
èŠãªã³ã³ããŒãã³ããå«ãç°¡åãªã¢ããªã±ãŒã·ã§ã³ãã§ããŸããã ãã®ã¢ããªã±ãŒã·ã§ã³ã¯ãReactNativeã䜿çšããŠéçºãããã¢ããªã±ãŒã·ã§ã³ã®åºç€ãšããŠäœ¿çšã§ããŸãã
ãã£ãŒã
æ©æ°èšã¢ããªã±ãŒã·ã§ã³ãéçºããŠãããããããã«å¿ããŠã枬å®çµæã衚瀺ããå¿
èŠããããŸãã æè¯ã®æ¹æ³ã¯ãç§ã«ã¯æãããããã£ãŒãã§ãã ãããã£ãŠãåçŽãªæ£ã°ã©ããäœæããŸããY軞ã¯ã¹ãããæ°ã瀺ããXã¯æéã瀺ããŸãã
ReactNativeã¯ãã®ãŸãŸã§ã¯canvasããµããŒãããŠããŸãããããã«ãcanvasã䜿çšããã«ã¯webviewãå¿
èŠã§ãã ãããã£ãŠã2ã€ã®ãªãã·ã§ã³ããããŸããåãã©ãããã©ãŒã ã®ãã€ãã£ãã³ã³ããŒãã³ããèšè¿°ããããã³ã³ããŒãã³ãã®æšæºã»ããã䜿çšããŸãã æåã®ãªãã·ã§ã³ã¯æãåŽåéçŽçã§ããããã®çµæãçç£çã§æè»ãªãœãªã¥ãŒã·ã§ã³ãåŸãããŸãã 2çªç®ã®ãªãã·ã§ã³ã«ã€ããŠèª¬æããŸãã
ããŒã¿ã衚瀺ããã«ã¯ããªããžã§ã¯ãã®é
åã®åœ¢åŒã§ã³ã³ããŒãã³ãã«ããŒã¿ã転éããŸãã
[ { label,
3ã€ã®ãã¡ã€ã«ãäœæããŸãã
app/components/chart.js app/components/chart-item.js app/components/chart-label.js
以äžã¯ããã£ãŒãã®ã¡ã€ã³ã³ã³ããŒãã³ãã®ã³ãŒãã§ãã
app/components/chart.js import ChartItem from './chart-item'; import ChartLabel from './chart-label'; class Chart extends Component { constructor(props) { super(props); let data = props.data || []; this.state = { data: data, maxValue: this.countMaxValue(data) } } countMaxValue(data) { return data.reduce((prev, curn) => (curn.value >= prev) ? curn.value : prev, 0); } componentWillReceiveProps(newProps) { let data = newProps.data || []; this.setState({ data: data, maxValue: this.countMaxValue(data) }); } renderBars() { return this.state.data.map((value, index) => ( <ChartItem value={value.value} color={value.color} key={index} barInterval={this.props.barInterval} maxValue={this.state.maxValue}/> )); } /* */ renderLabels() { return this.state.data.map((value, index) => ( <ChartLabel label={value.label} barInterval={this.props.barInterval} key={index} labelFontSize={this.props.labelFontSize} labelColor={this.props.labelFontColor}/> )); } render() { let labelStyles = { fontSize: this.props.labelFontSize, color: this.props.labelFontColor }; return( <View style={[styles.container, {backgroundColor: this.props.backgroundColor}]}> <View style={styles.labelContainer}> <Text style={labelStyles}> {this.state.maxValue} </Text> </View> <View style={styles.itemsContainer}> <View style={[styles.polygonContainer, {borderColor: this.props.borderColor}]}> {this.renderBars()} </View> <View style={styles.itemsLabelContainer}> {this.renderLabels()} </View> </View> </View> ); } } /* */ Chart.propTypes = { data: PropTypes.arrayOf(React.PropTypes.shape({ value: PropTypes.number, label: PropTypes.string, color: PropTypes.string })), // barInterval: PropTypes.number, // labelFontSize: PropTypes.number, // labelFontColor: PropTypes.string, // borderColor: PropTypes.string, // backgroundColor: PropTypes.string // } export default Chart;
ã°ã©ãåãå®è£
ããã³ã³ããŒãã³ãïŒ
app/components/chart-item.js export default class ChartItem extends Component { constructor(props) { super(props); this.state = { animatedTop: new Animated.Value(1000), value: props.value / props.maxValue } } componentWillReceiveProps(nextProps) { this.setState({ value: nextProps.value / nextProps.maxValue, animatedTop: new Animated.Value(1000) }); } render() { const { color, barInterval } = this.props; Animated.timing(this.state.animatedTop, {toValue: 0, timing: 2000}).start(); return( <View style={[styles.item, {marginHorizontal: barInterval}]}> <Animated.View style={[styles.animatedElement, {top: this.state.animatedTop}]}> <View style={{flex: 1 - this.state.value}} /> <View style={{flex: this.state.value, backgroundColor: color}}/> </Animated.View> </View> ); } } const styles = StyleSheet.create({ item: { flex: 1, overflow: 'hidden', width: 1, alignItems: 'center' }, animatedElement: { flex: 1, left: 0, width: 50 } });
ããŒã¿çœ²åã³ã³ããŒãã³ãã³ãŒãïŒ
app/components/chart-label.js export default ChartLabel = (props) => { const { label, barInterval, labelFontSize, labelColor } = props; return( <View style={[{marginHorizontal: barInterval}, styles.label]}> <View style={styles.labelWrapper}> <Text style={[styles.labelText, {fontSize: labelFontSize, color: labelColor}]}> {label} </Text> </View> </View> ); }
ãã®çµæãã³ã³ããŒãã³ãã®æšæºã»ããã䜿çšããŠå®è£
ãããåçŽãªãã¹ãã°ã©ã ãåŸãŸããã
æ©æ°èš
ReactNativeã¯ããããã¯ãŒã¯ããããŒã¿ãååŸããŠè¡šç€ºããåçŽãªã¢ããªã±ãŒã·ã§ã³ãäœæããããã®åºæ¬çãªããŒã«ã»ããã®ã¿ãåããããªãè¥ããããžã§ã¯ãã§ãã ãã ããã¿ã¹ã¯ãããã€ã¹èªäœã§ããŒã¿ãçæããããšã§ããå Žåããã©ãããã©ãŒã åºæã®èšèªã§ã¢ãžã¥ãŒã«ãäœæããå¿
èŠããããŸãã
ãã®æ®µéã§ã¯ãæ©æ°èšãäœæããå¿
èŠããããŸãã Objective-CãšJavaãããã³ããã€ã¹APIãç¥ããªããã°ããããè¡ãããšã¯å°é£ã§ãããå¯èœã§ãããã¹ãŠã¯æéã«äŸåããŸãã 幞ããªããšã«ãApache CordovaãAdobe PhoneGapãªã©ã®ãããžã§ã¯ãããããŸãã 圌ãã¯ããªãåããåžå Žã«åºãŠãããã³ãã¥ããã£ã¯åœŒãã®ããã«å€ãã®ã¢ãžã¥ãŒã«ãæžããŠããŸããã ãããã®ã¢ãžã¥ãŒã«ã¯ç°¡åã«ç§»æ€ããŠå¯Ÿå¿ã§ããŸãã ãã¹ãŠã®ããžãã¯ã¯å€æŽããããã€ã³ã¿ãŒãã§ã€ã¹ïŒããªããžïŒãæžãæããã ãã§æžã¿ãŸãã
IOSã«ã¯ãã¢ã¯ãã£ããã£ããŒã¿ãååŸããããã®åªããAPIïŒHealthKitïŒããããŸãã Appleã«ã¯åªããããã¥ã¡ã³ãããããéåžžã®åçŽãªã¿ã¹ã¯ã®å®è£
ãå«ãŸããŠããŸãã Androidã¯å¥ã®ç¶æ³ã§ãã ç§ãã¡ãæã£ãŠããã®ã¯ã»ã³ãµãŒã®ã»ããã ãã§ãã ããã«ãããã¥ã¡ã³ãã«ã¯ãAPI 19以éãã¹ãããã»ã³ãµãŒããŒã¿ãååŸã§ããããšãèšèŒãããŠããŸãã èšå€§ãªæ°ã®ããã€ã¹ãAndroidã§åäœããçã®äžåœã¡ãŒã«ãŒïŒæåãã©ã³ããå«ãïŒã ãã§ãªããäž»èŠãªã»ã³ãµãŒã»ããïŒå é床èšãåšå²å
ã»ã³ãµãŒãè¿æ¥ã»ã³ãµãŒïŒã®ã¿ãã€ã³ã¹ããŒã«ããŠããŸãã ãããã£ãŠãAndroid 4.4以éãšã¹ãããã»ã³ãµãŒãåããããã€ã¹ïŒããã³å€ãããã€ã¹ïŒã«ã€ããŠã¯ãã³ãŒããåå¥ã«èšè¿°ããå¿
èŠããããŸãã ããã«ããã枬å®ã®ç²ŸåºŠãåäžããŸãã
å®è£
ã«åãââããããŸãããã
ããã«äºçŽããŸãã ã³ãŒãã®å質ããaã³ããŸãã ç§ã¯ãããã®ããã°ã©ãã³ã°èšèªã«æåã«åºããããæéããªããªããšçŽæçãªã¬ãã«ã§ç解ããå¿
èŠããããŸããã
iOS
ã³ã³ãã³ããå«ã2ã€ã®ãã¡ã€ã«ãäœæããŸãã
ios/BHealthKit.h #ifndef BHealthKit_h #define BHealthKit_h #import <Foundation/Foundation.h> #import "RCTBridgeModule.h" @import HealthKit; @interface BHealthKit : NSObject <RCTBridgeModule> @property (nonatomic) HKHealthStore* healthKitStore; @end #endif ios/BHealthKit.m #import "BHealthKit.h" #import "RCTConvert.h" @implementation BHealthKit RCT_EXPORT_MODULE(); - (NSDictionary *)constantsToExport { NSMutableDictionary *hkConstants = [NSMutableDictionary new]; NSMutableDictionary *hkQuantityTypes = [NSMutableDictionary new]; [hkQuantityTypes setValue:HKQuantityTypeIdentifierStepCount forKey:@"StepCount"]; [hkConstants setObject:hkQuantityTypes forKey:@"Type"]; return hkConstants; } RCT_EXPORT_METHOD(askForPermissionToReadTypes:(NSArray *)types callback:(RCTResponseSenderBlock)callback){ if(!self.healthKitStore){ self.healthKitStore = [[HKHealthStore alloc] init]; } NSMutableSet* typesToRequest = [NSMutableSet new]; for (NSString* type in types) { [typesToRequest addObject:[HKQuantityType quantityTypeForIdentifier:type]]; } [self.healthKitStore requestAuthorizationToShareTypes:nil readTypes:typesToRequest completion:^(BOOL success, NSError *error) { if(success){ callback(@[[NSNull null]]); return; } callback(@[[error localizedDescription]]); }]; } RCT_EXPORT_METHOD(getStepsData:(NSDate *)startDate endDate:(NSDate *)endDate cb:(RCTResponseSenderBlock)callback){ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; NSLocale *enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionStrictStartDate]; [dateFormatter setLocale:enUSPOSIXLocale]; [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"]; HKSampleQuery *stepsQuery = [[HKSampleQuery alloc] initWithSampleType:[HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount] predicate:predicate limit:2000 sortDescriptors:nil resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) { if(error){ callback(@[[error localizedDescription]]); return; } NSMutableArray *data = [NSMutableArray new]; for (HKQuantitySample* sample in results) { double count = [sample.quantity doubleValueForUnit:[HKUnit countUnit]]; NSNumber *val = [NSNumber numberWithDouble:count]; NSMutableDictionary* s = [NSMutableDictionary new]; [s setValue:val forKey:@"value"]; [s setValue:sample.sampleType.description forKey:@"data_type"]; [s setValue:[dateFormatter stringFromDate:sample.startDate] forKey:@"start_date"]; [s setValue:[dateFormatter stringFromDate:sample.endDate] forKey:@"end_date"]; [data addObject:s]; } callback(@[[NSNull null], data ]); }]; [self.healthKitStore executeQuery:stepsQuery]; }; @end
次ã«ããããã®ãã¡ã€ã«ããããžã§ã¯ãã«è¿œå ããå¿
èŠããããŸãã Xcodeãéããã«ãŒããã£ã¬ã¯ããªãå³ã¯ãªãã¯->ããããžã§ã¯ãåãã«ãã¡ã€ã«ãè¿œå ããŸãã [æ©èœ]ã»ã¯ã·ã§ã³ã§ãHealthKitãæå¹ã«ããŸãã 次ã«ã[å
šè¬]-> [ãªã³ã¯ããããã¬ãŒã ã¯ãŒã¯ãšã©ã€ãã©ãª]ã»ã¯ã·ã§ã³ã§ã[+]ãã¯ãªãã¯ããŠHealthKit.frameworkãè¿œå ããŸãã
ãã€ãã£ãéšåãå®æããŸããã ããã«ããããžã§ã¯ãã®jséšåã®ããŒã¿ã®ååŸã«çŽæ¥é²ã¿ãŸãã
ãã¡ã€ã«app / services / health.ios.jsãäœæããŸãã
app/services/health.ios.js const { BHealthKit } = React.NativeModules; let auth;
Android
ã³ãŒãã¯èšå€§ã§ããããšãå€æãããããäœæ¥ã®ååã説æããŸãã
Android SDKã¯ã¹ãã¬ãŒãžãæäŸãããäžå®æéããŒã¿ãååŸã§ããã¹ãã¬ãŒãžã«ã¢ã¯ã»ã¹ããŸããããªã¢ã«ã¿ã€ã ã§ããŒã¿ãåä¿¡ããæ©èœã®ã¿ãæäŸããŸãã ãã®ããã«ãåžžã«ããã¯ã°ã©ãŠã³ãã§åäœããå¿
èŠãªã¿ã¹ã¯ãå®è¡ãããµãŒãã¹ã䜿çšãããŸãã äžæ¹ã§ãéåžžã«æè»æ§ããããŸããã20åã®æ©æ°èšãããã€ã¹ã«ã€ã³ã¹ããŒã«ãããåã¢ããªã±ãŒã·ã§ã³ã«ã¯ãæ®ãã®19ãšåãã¿ã¹ã¯ãå®è¡ããç¬èªã®ãµãŒãã¹ããããšããŸãããã
ç§ãã¡ã¯2ã€ã®ãµãŒãã¹ãå®çŸããŸãïŒã¹ãããã»ã³ãµãŒã®ããããã€ã¹ãšãªãããã€ã¹çšã§ãã ãããã¯android / app / src / main / java / com / awesomeproject / pedometer / StepCounterService.javaããã³android / app / src / main / java / com / awesomeproject / pedometer / StepCounterOldService.javaãã¡ã€ã«ã§ãã
ãã¡ã€ã«android / app / src / main / java / com / awesomeproject / pedometer / StepCounterBootReceiver.javaã§ãããã€ã¹ã®èµ·åæã«ãããã€ã¹ã«å¿ããŠã©ã®ãµãŒãã¹ãèµ·åããããã説æããŸãã
ãã¡ã€ã«android / app / src / main / java / com / awesomeproject / RNPedometerModule.javaããã³RNPedometerPackage.javaã§ãreactãšã®ã¢ããªã±ãŒã·ã§ã³æ¥ç¶ãå®è£
ããŸãã
Android / app / src / main / AndroidManifest.xmlã«è¡ãè¿œå ããŠãã»ã³ãµãŒã䜿çšããèš±å¯ãååŸããŸã
<uses-feature android:name="android.hardware.sensor.stepcounter" android:required="true"/> <uses-feature android:name="android.hardware.sensor.stepdetector" android:required=âtrue"/> <uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true" /> , , . <application> ⊠<service android:name=".pedometer.StepCounterService"/> <service android:name=".pedometer.StepCounterOldService" /> <receiver android:name=".pedometer.StepCounterBootReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> </application>
ã¢ãžã¥ãŒã«ãã¢ããªã±ãŒã·ã§ã³ã«æ¥ç¶ããã¢ããªã±ãŒã·ã§ã³ã®èµ·åæã«ãµãŒãã¹ãéå§ããŸãã
android/app/src/main/java/com/awesomeproject/MainActivity.java ⊠protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new RNPedometerPackage(this) ); } ⊠@Override public void onCreate(Bundle bundle) { super.onCreate(bundle); Boolean can = StepCounterOldService.deviceHasStepCounter(this.getPackageManager()); if (!can) { startService(new Intent(this, StepCounterService.class)); } else { startService(new Intent(this, StepCounterOldService.class)); } }
javascriptããŒãããããŒã¿ãååŸããŸãã ãã¡ã€ã«app / services / health.android.jsãäœæããŸã
const Pedometer = React.NativeModules.PedometerAndroid;
export default () => { return new Promise((resolve, reject) => { Pedometer.getHistory((result) => { try { result = JSON.parse(result);
ãã®çµæãhealth.ios.jsãšhealth.android.jsã®2ã€ã®ãã¡ã€ã«ãååŸããŸããããããã®ãã¡ã€ã«ã¯ããã€ãã£ããã©ãããã©ãŒã ã¢ãžã¥ãŒã«ãããŠãŒã¶ãŒã¢ã¯ãã£ããã£ã®çµ±èšæ
å ±ãåãåããŸãã ããã«ãã¢ããªã±ãŒã·ã§ã³å
ã®ã©ãã§ããåŒïŒ
import Health from '<path>health';
React Nativeã¯ããã¡ã€ã«ãã¬ãã£ãã¯ã¹ã«åºã¥ããŠç®çã®ãã¡ã€ã«ãããŠã³ãããŸãã ããã§ãè¿·ãããšãªããã®é¢æ°ã䜿çšã§ããŸããã¢ããªã±ãŒã·ã§ã³ã¯iOSãŸãã¯Androidã§å®è¡ãããŠããŸãã
ãã®çµæãåçŽãªæ©æ°èšã¢ããªã±ãŒã·ã§ã³ãäœæããç¬èªã®ã¢ããªã±ãŒã·ã§ã³ãéçºããéã«ééããå¿
èŠãããäž»èŠãªãã€ã³ãã調ã¹ãŸããã
æåŸã«ãReactNativeã®å©ç¹ãšæ¬ ç¹ã匷調ããããšæããŸãã
å©ç¹ïŒ
- JavaScriptã®çµéšãããéçºè
ã¯ãç°¡åã«ã¢ããªã±ãŒã·ã§ã³ãäœæã§ããŸãã
- 1ã€ã®ã¢ããªã±ãŒã·ã§ã³ãéçºãããšãããã«AndroidãšIOSã§å®è¡ããæ©äŒãåŸãããŸãã
- ReactNativeã«ã¯ãå€ãã®å Žåããã¹ãŠã®èŠä»¶ãã«ããŒããå®è£
æžã¿ã³ã³ããŒãã³ãã®ããªã倧ããªã»ããããããŸãã
- ããŸããŸãªã¢ãžã¥ãŒã«ãè¿
éã«äœæããŠããã¢ã¯ãã£ããªã³ãã¥ããã£ã
çæïŒ
- åãã³ãŒããäž¡æ¹ã®ãã©ãããã©ãŒã ã§åžžã«ã¹ã ãŒãºã«æ©èœãããšã¯éããŸããïŒå€ãã®å Žåã衚瀺ã®åé¡ïŒ
- ç¹å®ã®ã¿ã¹ã¯ã®ããã«ãå€ãã®å Žåãå®è£
ãããã¢ãžã¥ãŒã«ããªããèªåã§ããããèšè¿°ããå¿
èŠããããŸãã
- ããã©ãŒãã³ã¹ã PhoneGapãCordovaãšæ¯èŒãããšãåå¿ã¯éåžžã«é«éã§ããããã€ãã£ãã¢ããªã±ãŒã·ã§ã³ã®æ¹ãé«éã§ãã
ReactNativeãéžæããã®ãé©åãªã®ã¯ãã€ã§ããïŒ
ãµãŒããŒããããŒã¿ãåä¿¡ããŠââ衚瀺ããåçŽãªã¢ããªã±ãŒã·ã§ã³ãéçºããå¿
èŠãããå Žåãéžæã¯æããã§ãã ã¯ãŒã«ãªãã¶ã€ã³ãå®è£
ããã¿ã¹ã¯ã«çŽé¢ããŠããå Žåãããã©ãŒãã³ã¹ãéèŠã§ããããåžè²©ã®ã³ã³ããŒãã³ãã䜿çšããŠè§£æ±ºããã®ãé£ããã¿ã¹ã¯ãããå Žåã¯ãæ€èšãã䟡å€ããããŸãã ã»ãšãã©ã¯ãã©ãããã©ãŒã ã®ãã€ãã£ãèšèªã§äœæããå¿
èŠãããããããããããã©ããããæ§ç¯ããããšã¯ééããªãæè¯ã®éžæè¢ã§ã¯ãããŸããã
ãæž
èŽããããšãããããŸããã
äœæè
ïŒ greebn9k ïŒSergey GribnyakïŒã boozzd ïŒDmitry Shapovalenko ïŒã silmarilion ïŒAndrey KhakharevïŒ