How to send SMS programatically in React Native with phone credit - react-native

I was looking for a way to send an SMS programmatically in React Native without using 3rd Party APIs like Twilio or Firebase etc. My intention was to use phone credit / the available airtime in my SIM Card.

I found the solution from the following link but edited it a bit since the original wa giving errors during compile:
Note: This solution requires you to extend your current React Native code base with Native Java code modules. But don't let that scare you.
Link: Sending Direct SMS In React-Native Android by Fateme Fazli
Step 1: Create SendSMSModule.java
Go into your android/app/src/main/java/com/your_project_name folder to create the DirectSmsModule.java module, use the below Java code.
//DirectSmsModule.java : This is the name of the Java Class/File
package com.your_project_name; //make sure to change to your project's actual name.
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.uimanager.IllegalViewOperationException;
import android.telephony.SmsManager; //++ make sure this package is available always
public class DirectSmsModule extends ReactContextBaseJavaModule {
public DirectSmsModule(ReactApplicationContext reactContext) {
super(reactContext); //required by React Native
}
#Override
//getName is required to define the name of the module represented in JavaScript
public String getName() {
return "DirectSms";
}
#ReactMethod
public void sendDirectSms(String phoneNumber, String msg) {
try {
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNumber, null, msg, null, null);
System.out.println("message sent successfully.");
} catch (Exception ex) {
System.out.println("couldn't send message.");
}
}
}
Step 2: Create DirectSmsPackage.java Module
In the same folder android/app/src/main/java/com/your_project_name where you now have probably 3 Java files, add this 4th one: DirectSmsPackage.java
//DirectSmsPackage.java
package com.your_project_name;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.enoxscanner.DirectSmsModule; // enoxscanner should be replaced with your own package name
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class DirectSmsPackage implements ReactPackage {
#Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
#Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
//this is where you register the module
modules.add(new DirectSmsModule(reactContext));
return modules;
}
}
Step 3: Register DirectSmsPackage
Now register the module we have just created above there. This is almost the same as you do with those packages that you have to manually link after adding or installing them.
In the same folder, locate your MainApplication.java file and locate the below section of code then add the line highlighted as add this line: Note, you are editing the getPackages() function
#Override
protected List<ReactPackage> getPackages() {
#SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new DirectSmsPackage()); //++ add this line here ++
return packages;
}
Step 4: Call the sendDirectSMS in you RN Script
import React, { Component } from 'react';
import { NativeModules, PermissionsAndroid } from 'react-native';
//++ import NativeModules since we are using a Native external module
...
const DirectSms = NativeModules.DirectSms;
export class SMSScreen extends Component {
sendDirectSms = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.SEND_SMS,
{
title: 'Tadiwanashe App Sms Permission',
message:
'Tadiwanashe App needs access to your inbox ' +
'so you can send messages in background.',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
},
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
DirectSms.sendDirectSms('0772......', 'This is a direct message from your app.');
} else {
console.log('SMS permission denied');
}
} catch (err) {
console.warn(err);
}
}
render() {
return (
<View style={styles.mother_container}>
<View style={styles.container}>
<TextInput secureTextEntry={true} style={styles.input}
underlineColorAndroid="transparent"
placeholder="Enter PIN."
placeholderTextColor="black"
autoCapitalize="none"
onChangeText={this.handlePIN}
textAlign={'center'}
/>
<TouchableOpacity
style={styles.button}
onPress={() => this.sendDirectSms()}>
<Text style={styles.submitButtonText} selectTextOnFocus={true}> Submit </Text>
</TouchableOpacity>
</View>
<AppFooter bgColor='#fff' textColor='grey' />
</View>
)
}
}
export default SMSScreen ;
NOTE:
Such applications that auto Send SMSs might not be allowed on Google.
You will not receive SMSs until your app is Granted permission by the
user, hence we imported PermissionsAndroid.
The link above will give you proper explanation of much of the
details, this is not entirely my work but simply edited accordingly
after realising that the original code for the article had some
errors and as well the article resides on a platform which makes it
hard to give proper contributions compared to SO.

Related

React-native fbsdk-next asks just for public_profile permission

I have next issue: my react-native app doesn't ask fb about all permissions from list, just about public_profile permission. System iOS.
My code is:
LoginManager.logInWithPermissions(['public_profile', 'user_friends', 'user_posts', 'email']).then(
(result) => {
if (result.isCancelled) {
alert('Login was cancelled')
} else {
console.log("RESULT_IS", result)
AccessToken.getCurrentAccessToken().then((data) => {
const accessToken = data.accessToken.toString();
const userID = data.userID.toString();
});
Profile.getCurrentProfile().then((data) => {
console.log('DATA', data);
})
}
},
);
console.log('DATA', data) shows that imageURL, userID and name has a value, and email, firstName, lastName, middleName are null.
console.log("RESULT_IS", result) shows RESULT_IS {"declinedPermissions": [], "grantedPermissions": ["public_profile"], "isCancelled": false}
So I am using Profile.getCurrentProfile() to get additional data from fb (for example email). To do that I asked fb about additional permissions adding them to LoginManager.logInWithPermissions(). As I understood my app doesn't ask about fb all permissions just about public_profile. Why does it happened and how can I fix it?
I had the same issue too.
On Android, in the path below
node_modules/react-native fbsdk-next/android/src/main/java/com/facebook/reactnative/androidsdk/FBProfileModule.java
You can import profile information right away by editing the file as shown below.
I also referenced other people's content.
So have a nice day!
FBProfileModule.java
package com.facebook.reactnative.androidsdk;
import com.facebook.Profile;
import com.facebook.ProfileTracker; // add
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.annotations.ReactModule;
import androidx.annotation.NonNull;
/**
* This is a {#link NativeModule} that allows JS to use FBSDKProfile info of the current logged user.
+ * current logged user // add
*/
#ReactModule(name = FBProfileModule.NAME)
public class FBProfileModule extends ReactContextBaseJavaModule {
public static final String NAME = "FBProfile";
private ProfileTracker mProfileTracker; // add
public FBProfileModule(ReactApplicationContext reactContext) {
super(reactContext);
}
#NonNull
#Override
public String getName() {
return NAME;
}
/**
* Get the current logged profile.
* #param callback Use callback to pass the current logged profile back to JS.
*/
#ReactMethod
public void getCurrentProfile(Callback callback) {
//Return the profile object as a ReactMap.
// add
if (Profile.getCurrentProfile() == null) {
mProfileTracker = new ProfileTracker() {
#Override
protected void onCurrentProfileChanged(Profile oldProfile, Profile currentProfile) {
callback.invoke(Utility.profileToReactMap(currentProfile));
mProfileTracker.stopTracking();
}
};
} else {
callback.invoke(Utility.profileToReactMap(Profile.getCurrentProfile()));
}
// remove
// callback.invoke(Profile.getCurrentProfile() == null
// ? null
// : Utility.profileToReactMap(Profile.getCurrentProfile()));
}
}
Facebook provides public profile by default if you want anything else you will have to add it by visiting your app in facebook developer console.
Go to your app
Open app Review
In app review open Permissions and Features
In Permissions and Features you can see multiple options
Select your desired permission and try again you will get that value as well.
I hope it helps you.

how to add Headless js log geolocation for continuous interval

In Android Manifest I have added all the required permission for geolocation and added the service name as TimeTracking
package com.timetracking;
import android.content.Intent;
import android.os.Bundle;
import com.facebook.react.HeadlessJsTaskService;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.jstasks.HeadlessJsTaskConfig;
import javax.annotation.Nullable;
public class TimeTracking extends HeadlessJsTaskService {
#Override
protected #Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
Bundle extras = intent.getExtras();
WritableMap data = extras != null ? Arguments.fromBundle(extras) : null;
return new HeadlessJsTaskConfig(
"TimeTracking", // Use the registered headless Task here
data,
500,
true);
}
}
And in app.js page in react native I have called it.
AppRegistry.registerHeadlessTask('TimeTracking', () => TimeTracking);
but nothing is displaying in console.Please can somebody tell the method to get timeInterval of location.
Thanks in advance.

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

Android Warning: Native component for "AIRMap" does not exist

I have successfully added an Airbnb map in react app.
But when I am adding an Airbnb map view to existing android native application. I am getting always empty map with red border.
I am using RN 0.40 and react-native-maps 0.13.0.
After the react-native link commands. Then android always have the Warning:
Native component for "AIRMap" does not exist.
Running application "App" with appParams:
{"initialProps":{},"rootTag":1}. DEV === true, development-level
warning are ON, performance optimizations are OFF
Here is my MainApplication.java file
package punchh.customreactcomponent;
import android.app.Application;
import com.airbnb.android.react.maps.MapsPackage;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import java.util.Arrays;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
#Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
#Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new MapsPackage()
);
}
};
#Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
#Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, false);
}
}
In my case I was getting that error (and a blank screen) when attempting to run an app on an android simulator. I fixed the issue with applying the next steps:
1 - Running react-native link then restarted the js server (react-native start) and redeployed the app on simulator (react-native run-android)
2 - Running on a real device or on a simulator based on GoogleApi system image. If you get a googleApi not supported message then add some packages in android studio and create a new device as described in next link:
My application relies Google play services, which is not supported by your device. contact the manufacturer for assistance
The working configuration for my virtual device:
3 - Adding the Google_API_KEY (If you don't have one you'll have to create it) in manifest file (android\app\src\main\AndroidManifest.xml):
<!-- make sure it's a child of application -->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="Your Google maps API Key Here"/>
Started the device, restarted js server, redeployed on device
Everything should have worked but I faced an issue with my google_api_key (an empty yellow map) like in the next picture:
so I created and enabled a new one specific for my project here
https://developers.google.com/maps/documentation/android-api/signup#release-cert
Restarted JS server, ran react-native run-android and it worked:
To debug I used adb logcat in a separate terminal.
Inspired from:
https://github.com/airbnb/react-native-maps/blob/master/docs/installation.md
and from
https://github.com/airbnb/react-native-maps/issues/118
If the map still doesn't show you might need some styling. I added a basic one to my component like this:
import React from 'react'
import MapView from 'react-native-maps';
import {
View, StyleSheet
} from 'react-native'
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
height: 400,
width: 400,
justifyContent: 'flex-end',
alignItems: 'center',
},
map: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
width: 300,
height: 300
},
});
export default class MyMap extends React.Component {
render() {
const { region } = this.props;
return (
<View style ={styles.container}>
<MapView
style={styles.map}
region={{
latitude: 44.42,
longitude: 26.10,
latitudeDelta: 0.015,
longitudeDelta: 0.0121
}}
>
</MapView>
</View>
);
}
}
ITS WORKING
it repeated this failure to recreate successfull working react-native-maps
react - 16.3.1
react-native - 0.55.4
react-native-maps - 0.21.0
step 1
i created app like this
$react-native init tank1
step 2
I followed installation from react-native-maps
step 3
follow installation from Moses Lucas post important
step 4
in MainApplication.java
use below code without #Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new MapsPackage()
);
}
Note 1
I had doub't about synatx #import GoogleMaps; in AppDelegete.m but this too works fine
Note 2
If you had run react-native link
please check settings.gradle it should not contain duplicate entries
Note 3
Do not remove include ':app' from settings.gradle
I fixed the problem by adding MapsPackage to the getPackages method in MainApplication.java file.
no need to add #Override
My Code looks like this:
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MapsPackage()
);
}