How to get the phone state in React Native - react-native

I'm using react native on and android project, and i'm in need of detect the call state of the actives calls of the android device, like incoming, connected, and etc.
I need the phone number of the incoming/outgoin cellphone too.
Thanks in advance!

With react native, you can use react-native-call-state to check the state of the call, using like this:
import React, { DeviceEventEmitter } from 'react-native'
import CallState from 'react-native-call-state';
componentWillMount() {
CallState.startListener();
this.subscription = DeviceEventEmitter.addListener('callStateUpdated', data => { console.warn(JSON.stringify(data)); });
}
componentWillUnmount() {
CallState.stopListener();
}
using java, you can use TelephonyManager, with a setup like:
public class MyPhoneStateListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
handleRinging(incomingNumber);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
handleOffHook();
break;
case TelephonyManager.CALL_STATE_IDLE:
handleIdle();
break;
}
super.onCallStateChanged(state, incomingNumber);
}
}
To get the phone number of a call, you can use react-native-call-detection, here you can have a full example of how to make it, from the beginning to the end.

Related

ReactNative RCTResponseSenderBlock or Callback with return value

We have a React Native Module, with iOS and Android support.
At some point, the native iOS and Android components will pass a parameter to JavaScript and ask for info.
We saw in the docs that we can use Callbacks. Knowing that callbacks are functions, it can takes parameters and return values.
For simplicity, I'll share one method from the React Native docs to demonstrate our problem.
// iOS
RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback) {
NSArray *events = ...
id result = callback(#[[NSNull null], events]);
// ~~~^~~~
// This is not allowed, RCTResponseSenderBlock returns void
}
// Android
#ReactMethod
public void findEvents(Callback errorCallback, Callback successCallback) {
Event events[] = ...
try {
Object result = successCallback.invoke(events);
// ~~~~^~~~~
// This is not allowed, Callback returns void
} catch (IllegalViewOperationException e) {
errorCallback.invoke(e.getMessage());
}
}
In this example, we pass events, and ask for result from JavaScript. In JavaScript, code should be:
CalendarManager.findEvents((error, events) => {
if (error) {
console.error(error);
} else {
return { "success": true } // we want to receive this in Native code.
}
});
We also looked at Promises and Event Emitters. But none of them designed for returns.

Having Problem with React-native-gesture-handler(cannot find symbol String overflow = ((ReactViewGroup) view).getOverflow();)

I am having an issue with react-native-gesture-handler. Whenever I link my react-native-gesture-handler to my project it stops working and shows this error. But after unlinking react-native-gesture-handler from my project the application work fine. But as I need to navigate from several screens, I need gesture handler.
First I thought it was the problem of the react-native version as I was using react-native version 0.57.0 but it's not working on 0.58.0 and 0.55.4 either.
package com.swmansion.gesturehandler.react;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import com.facebook.react.uimanager.PointerEvents;
import com.facebook.react.uimanager.ReactPointerEventsView;
import com.facebook.react.views.view.ReactViewGroup;
import com.swmansion.gesturehandler.PointerEventsConfig;
import com.swmansion.gesturehandler.ViewConfigurationHelper;
public class RNViewConfigurationHelper implements ViewConfigurationHelper {
#Override
public PointerEventsConfig getPointerEventsConfigForView(View view) {
PointerEvents pointerEvents;
pointerEvents = view instanceof ReactPointerEventsView ?
((ReactPointerEventsView) view).getPointerEvents() :
PointerEvents.AUTO;
// Views that are disabled should never be the target of pointer events. However, their children
// can be because some views (SwipeRefreshLayout) use enabled but still have children that can
// be valid targets.
if (!view.isEnabled()) {
if (pointerEvents == PointerEvents.AUTO) {
return PointerEventsConfig.BOX_NONE;
} else if (pointerEvents == PointerEvents.BOX_ONLY) {
return PointerEventsConfig.NONE;
}
}
switch (pointerEvents) {
case BOX_ONLY: return PointerEventsConfig.BOX_ONLY;
case BOX_NONE: return PointerEventsConfig.BOX_NONE;
case NONE: return PointerEventsConfig.NONE;
}
return PointerEventsConfig.AUTO;
}
#Override
public View getChildInDrawingOrderAtIndex(ViewGroup parent, int index) {
if (parent instanceof ReactViewGroup) {
return parent.getChildAt(((ReactViewGroup) parent).getZIndexMappedChildIndex(index));
}
return parent.getChildAt(index);
}
#Override
public boolean isViewClippingChildren(ViewGroup view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && !view.getClipChildren()) {
if (view instanceof ReactViewGroup) {
String overflow = ((ReactViewGroup) view).getOverflow();
return "hidden".equals(overflow);
}
return false;
}
return true;
}
}
You can try manual linking.
Also check this issue out :
https://github.com/kmagiera/react-native-gesture-handler/issues/205
If you get the problem in Android, but not iOS, it could be that you need to add a polyfill for symbols. I can't remember where I found this, but I have used it in my own projects and it works. Just stick it in your index.js:
if (Platform.OS === 'android') {
if (typeof Symbol === 'undefined') {
if (Array.prototype['##iterator'] === undefined) {
Array.prototype['##iterator'] = function() {
let i = 0;
return {
next: () => ({
done: i >= this.length,
value: this[i++]
})
};
};
}
}
}

"undefined is not a function" when create android native module in ReactNative

I'm following ReactNative Native Module Guide to write the java class that can be used in JS side. The exported method is show from class ToastModule(exported as ToastAndroid). The show method is below:
public void show(String message, int duration) {
Toast.makeText(getReactApplicationContext(), message, duration).show();
}
All work as expected with the toast button appear when I invoke ToastAndroid.show from Button onPress handler.
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Button,
NativeModules,
} from 'react-native';
const ToastAndroid = NativeModules.ToastAndroid
export default class App extends Component {
handleBTNPressed(){
ToastAndroid.show('Awesome', ToastAndroid.SHORT);
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!!
</Text>
<Button title='click me' onPress={()=>this.handleBTNPressed()}/>
</View>
);
}
}
However, when I further change the function name from
#ReactMethod
public void show(String message, int duration) {
Toast.makeText(getReactApplicationContext(), message, duration).show();
}
to
#ReactMethod
public void showAgain(String message, int duration) {
Toast.makeText(getReactApplicationContext(), message, duration).show();
}
I encounter the following error:"undefined is not a function"
this error shows again if I add a new exported method as following:
#ReactMethod
public void showAgain2(String message, int duration) {
String mes = "Hi " + message;
Toast.makeText(getReactApplicationContext(), message, duration).show();
}
Is there anyone know which step I goes incorrectly?
EDIT==========================
There might already be a ToastAndroid in ReactNative, so I change the name to MyToastExample. However, now the error become the following
Does anyone encounter the same issue?
In this step, check if you have import the right ToastModule, because ReactNative also have a class Called ToastModule.
Check if this line import com.facebook.react.modules.toast.ToastModule; exist in *ReactPackage.java
Try using import instead of require.
In my situation, I was using:
var Contacts = require( "react-native-unified-contacts" );
and I was getting the undefined is not function error.
However, changing to:
import Contacts from "react-native-unified-contacts";
fixed the issue for me.
Clearly require and import treat the modules differently.

React Native Get battery status / level Using Native Modules

I am writing a react native app to get IOS and Android Battery status. I search through the net and found few libraries which can get battery level of the phone.
https://github.com/robinpowered/react-native-device-battery
https://github.com/remobile/react-native-battery-status
https://github.com/oojr/react-native-battery
Every library has issues when I try that and not much support for the developer when ask a question on git hub.
Can any one provide me better solution or library to get Battery status of IOS and Android.
Thanks in advance
I wrote my own IOS and Android classes to get the Battery Status. Here are the steps if any one interested on that,
For IOS,
Open the iOS project in XCode
Create 2 new files call BatteryStatus.h and BatteryStatus.m
BatteryStatus.h file should contain following code
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#interface BatteryStatus : RCTEventEmitter <RCTBridgeModule>
#end
BatteryStatus.m file should
#import "BatteryStatus.h"
#implementation BatteryStatus
RCT_EXPORT_MODULE(BatteryStatus)
- (instancetype)init
{
if ((self = [super init])) {
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
}
return self;
}
RCT_EXPORT_METHOD(hide) {
}
RCT_EXPORT_METHOD(updateBatteryLevel:(RCTResponseSenderBlock)callback)
{
callback(#[[self getBatteryStatus]]);
}
//manually get battery status by calling following method
-(NSDictionary*)getBatteryStatus
{
float batteryLevel = [UIDevice currentDevice].batteryLevel;
NSObject* currentLevel = nil;
currentLevel = [NSNumber numberWithFloat:(batteryLevel * 100)];
NSMutableDictionary* batteryData = [NSMutableDictionary dictionaryWithCapacity:2];
[batteryData setObject:currentLevel forKey:#"level"];
return batteryData;
}
#end
Inside your react native app, inside your js file add following code
import { NativeModules } from 'react-native';
constructor(props) {
super(props);
this.state = {
batteryLevel: null,
};
}
componentDidMount() {
NativeModules.BatteryStatus.updateBatteryLevel((info) => {
//console.log(info.level)
const level = Math.ceil(info.level);
this.setState({ batteryLevel: level});
});
}
For IOS above code is working for me to get the battery level
For Android,
Open the Android project in Android Studio
Create a group call BatteryStatus and include 2 Files named , BatteryStatusModule.java and BatteryStatusPackage.java
BatteryStatusModule.java Should contain following code
package com.yourproject.BatteryStatus;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class BatteryStatusModule extends ReactContextBaseJavaModule {
public BatteryStatusModule(ReactApplicationContext reactContext) {
super(reactContext);
}
#Override
public String getName() {
return "BatteryStatus";
}
#ReactMethod
public void getBatteryStatus(Callback successCallback) {
Intent batteryIntent = getCurrentActivity().registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
if(level == -1 || scale == -1) {
level = 0;
}
//System.out.print("battery level");
//System.out.print(level);
successCallback.invoke(null ,((float)level / (float)scale) * 100.0f);
}
}
BatteryStatusPackage.java should contain following code
package com.yourproject.BatteryStatus;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BatteryStatusPackage implements ReactPackage {
#Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new BatteryStatusModule(reactContext));
return modules;
}
#Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
#Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
Inside MainApplication.java include following code
#Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new MapsPackage(),
new BatteryStatusPackage()
);
}
Inside your react native app, inside your js file add following code
import { NativeModules } from 'react-native';
constructor(props) {
super(props);
this.state = {
batteryLevel: null
};
}
getBatteryLevel = (callback) => {
NativeModules.BatteryStatus.getBatteryStatus(callback);
}
6.Call it something like this:
componentDidMount() {
this.getBatteryLevel((batteryLevel) => {
console.log(batteryLevel);
});
}
For Android above code is working for me to get the battery level
Hope this will help some one to get battery level for IOS and ANDROID
We can use react-native-device-info for getting any device's specific information.
Install with command
npm install --save react-native-device-info
# or
yarn add react-native-device-info
Get the battery level of the device as a float comprised between 0 and 1 with getBatteryLevel().
DeviceInfo.getBatteryLevel().then(batteryLevel => {
console.log(batteryLevel);
// 0.759999
});
Note:
Returns -1 on the iOS Simulator
Just some addition to the right answer. You have to override the 'supportedEvents' function in the BatteryStatus.m file to make it work like this :
-(NSArray<NSString *> *)supportedEvents{
return #[#"level"];
}

React Native Android Native UI Component the #ReactProps doesn't execute

I have build a map Native UI Component at the Android platform. When the view is imported in the view as this
<AMapView style={styles.mapContainer} mode={2} onRegionChange={this._onReginChange.bind(this)}/>
The onRegionChange event is executed but the property method doesn't execute. enter link description here
class AMapCustomView extends Component {
constructor(props) {
super(props)
this._onRegionChange = this._onRegionChange.bind(this)
}
_onRegionChange(event: Event) {
if (!this.props.onRegionChange) {
return
}
this.props.onRegionChange(event.nativeEvent)
}
render() {
return <RCTAMap {...this.props} onRegionChange={this._onRegionChange}/>
}
}
AMapCustomView.propTypes = {
...View.propTypes,
mode: PropTypes.number,
onRegionChange: PropTypes.func
}
var RCTAMap = requireNativeComponent('RCTAMap', AMapCustomView)
module.exports = AMapCustomView;
Java Code:
#Override
public Map getExportedCustomDirectEventTypeConstants() {
return MapBuilder.of(
AMapLocationEvent.EVENT_NAME, MapBuilder.of("registrationName", "onRegionChange")
);
}
#ReactProp(name="mode", defaultInt = 1)
public void setMode(AMapView mapView, int type) {
Log.d(TAG, "mode:" + type);
}
Make sure you import com.facebook.react.uimanager.annotations.ReactProp;, I think the path used to change and the old ReactProp will no more work in more recent React Native version.