React Native Get battery status / level Using Native Modules - react-native

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"];
}

Related

Minecraft Forge 1.12.2 - Item Textures Not Loading

When following Cubicoder's modding tutorial for Forge 1.12.2, and creating my first item, the texture for the item will not load. I have double checked all of my code against his code. I have my latest log here. I have my registration handler RegistrationHandler.java down below.
package notacyborg.tutorialmod;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraftforge.event.RegistryEvent.Register;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import notacyborg.tutorialmod.util.RegistryUtil;
#EventBusSubscriber(modid = TutorialMod.MODID)
public class RegistrationHandler
{
#SubscribeEvent
public static void registerItems(Register<Item> event)
{
final Item[] items = {
RegistryUtil.setItemName(new Item(), "first_item").setCreativeTab(CreativeTabs.MISC)
};
event.getRegistry().registerAll(items);
}
}
ModelRegistrationHandler.java
package notacyborg.tutorialmod.client;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.item.Item;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import notacyborg.tutorialmod.TutorialMod;
import notacyborg.tutorialmod.init.ModItems;
#EventBusSubscriber(value = Side.CLIENT, modid = TutorialMod.MODID)
public class ModelRegistrationHandler
{
#SubscribeEvent
public static void registerModels(ModelRegistryEvent event)
{
registerModel(ModItems.FIRST_ITEM, 0);
}
private static void registerModel(Item item, int meta)
{
ModelLoader.setCustomModelResourceLocation(item, meta,
new ModelResourceLocation(item.getRegistryName(), "inventory"));
}
}
And my first_item.json model file.
{
"parent": "item/generated",
"textures": {
"layer0": "tutorialmod:textures/items/first_item"
}
}
Any help is appreciated!
Your error log says that it was not able to find the model file of your first_item. Make sure that you have put your first_item.json (model file) in assets/Your-Mod-ID/models/item/first_item.json
In your first_item.json file, line 4 should be:
"textures": {
"layer0": "tutorialmod:item/first_item"
}
Try it out and post an error log too if you encounter any further errors.

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++]
})
};
};
}
}
}

How to send a click event from React Native using UI component bridge in iOS / Objective-C

My app has a need to call a method in a native iOS SDK (Esri Mapping), and I have implemented sending an event from RN(0.55) to Android across the bridge with the following code:
BaseEsriMap Component:
import React, { Component } from 'react';
import { requireNativeComponent, UIManager, findNodeHandle } from 'react-native';
const RNTMap = requireNativeComponent('RNTEsriMaps', null);
class BaseEsriMap extends Component {
recenterMap = () => {
console.log('Recenter requested');
UIManager.dispatchViewManagerCommand(
findNodeHandle(this.mapRef),
UIManager.RNTEsriMaps.Commands.recenterMap,
[],
);
};
render() {
return (
<RNTMap
style={ { flex: 1 } }
ref={ (component) => { this.mapRef = component; } }
/>
);
}
}
export default BaseEsriMap;
RNTEsriMapsManager:
...
public class RNTEsriMapsManager extends ViewGroupManager<MapViewLayout> {
public static final String REACT_CLASS = "RNTEsriMaps";
public static final int COMMAND_RECENTER_MAP = 1;
#Override
protected MapViewLayout createViewInstance(ThemedReactContext reactContext) {
MapViewLayout mapViewLayout = new MapViewLayout(reactContext);
return mapViewLayout;
}
...
#Override
public Map<String,Integer> getCommandsMap() {
return MapBuilder.of(
"recenterMap",
COMMAND_RECENTER_MAP
);
}
#Override
public void receiveCommand(
MapViewLayout esriMapView,
int commandType,
#Nullable ReadableArray args) {
Assertions.assertNotNull(esriMapView);
Assertions.assertNotNull(args);
switch (commandType) {
case COMMAND_RECENTER_MAP: {
Log.d("Recenter", "COMMAND_RECENTER_MAP");
return;
}
default:
throw new IllegalArgumentException(String.format(
"Unsupported command %d received by %s.",
commandType,
getClass().getSimpleName()));
}
}
}
I believe the code should be added in my RNTEsriMapsManager.m.
#import "RNTEsriMapsManager.h"
#import "EsriMapView.h"
#implementation RNTEsriMapsManager
RCT_EXPORT_MODULE()
-(UIView*)view {
EsriMapView *mapView = [[EsriMapView alloc] init];
mapView.mapDelegate = self;
return mapView;
}
// recenterMap implementation here?
#end
How can I extend my code to do the same on iOS?
One way you can do it, is by exposing a method:
#import "RNTEsriMapsManager.h"
#import "EsriMapView.h"
#interface RNTEsriMapsManager ()
#property (nonatomic, strong) EsriMapView *mapView;
#end
#implementation RNTEsriMapsManager
RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(recenterMap)
{
NSLog(#"Method called to recenter map");
[self.mapView mapViewsFunctionToRecenter];
}
-(UIView*)view {
if (!self.mapView) {
self.mapView = [[EsriMapView alloc] init];
self.mapView.mapDelegate = self;
}
return self.mapView;
}
Then in your javascript, you can call it as a function on your RNTMap const:
import { NativeModules } from 'react-native';
const mapManager = NativeModules.RNTEsriMapsManager;
mapManager.recenterMap();
I made the map view a property to have access to it in the method, because I'm assuming it has a method that could be used to have it recenter.

react-native landscape mode Orientation

Im still beginner and here is one page that I want it to display with landscape mode when I open up the page. I installed react-native-orientation, but im not sure how I can use this.
I want landscape mode when I open the app, so I believe that I should set Orientation when I use, componentWillMount(){
Orientation
}
but im not sure how to set it up... could anyone tell me how?
Try Following package may be help you.
react-native-orientation
only this one line add on your project in your
android:screenOrientation="landscape"
android->app->src->main->AndroidManifest.xml
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:screenOrientation="landscape"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I came across the same issue instead of using third party module I created my own.
My React Native Module:
public class OrientationHelperModule extends ReactContextBaseJavaModule {
private static final String TAG = OrientationHelperModule.class.getSimpleName();
private static final String MODULE_NAME = "OrientationHelperModule";
private final ReactApplicationContext reactAppContext;
#Override
public String getName() {
return MODULE_NAME;
}
public OrientationHelperModule(ReactApplicationContext reactAppContext) {
super(reactAppContext);
this.reactAppContext = reactAppContext;
}
#ReactMethod
public void lockLandscape() {
OrientationUtils.lockOrientationLandscape(getCurrentActivity());
}
#ReactMethod
public void unlockOrientation() {
OrientationUtils.unlockOrientation(getCurrentActivity());
}
#ReactMethod
public void lockPortrait() {
OrientationUtils.lockOrientationPortrait(getCurrentActivity());
}
}
The Helper class to handle orientation lock
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Build;
import android.view.Surface;
import android.view.WindowManager;
/* * This class is used to lock orientation of Android app in any Android devices
*/
public class OrientationUtils {
private OrientationUtils() {
}
/**
* Locks the device window in landscape mode.
*/
public static void lockOrientationLandscape(Activity activity) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
}
/**
* Locks the device window in portrait mode.
*/
public static void lockOrientationPortrait(Activity activity) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
/**
* Locks the device window in actual screen mode.
*/
public static void lockOrientation(Activity activity) {
final int orientation = activity.getResources().getConfiguration().orientation;
final int rotation = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
.getRotation();
// Copied from Android docs, since we don't have these values in Froyo
// 2.2
int SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8;
int SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9;
// Build.VERSION.SDK_INT <= Build.VERSION_CODES.FROYO
if (!(Build.VERSION.SDK_INT <= Build.VERSION_CODES.FROYO)) {
SCREEN_ORIENTATION_REVERSE_LANDSCAPE = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
SCREEN_ORIENTATION_REVERSE_PORTRAIT = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
}
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90) {
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
} else if (rotation == Surface.ROTATION_180 || rotation == Surface.ROTATION_270) {
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
}
}
}
/**
* Unlocks the device window in user defined screen mode.
*/
public static void unlockOrientation(Activity activity) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
}
}
Import it in React Native
'use strict';
import { NativeModules } from 'react-native';
module.exports = NativeModules.OrientationHelperModule;
Import OrientationHelperModule in your component
import OrientationHelperModule from './src/modules/OrientationHelperModule'
And use it to lock orientation
componentDidMount = () => {
OrientationHelperModule.lockLandscape();
}

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.