Accessing the same persistent store from Swift and React Native - ios

We're considering using React Native for one of our Screens - for fun, to check it and to get a better grasp of the possibilities, but even before w start I need some answers, so we're sure React Native and it's environments can meet our requirements.
In this question I'd like to specifically ask about persisting data and accessing it.
In our app we focus on offline experience, as it's one of the most crucial points for us. On iOS we have a couple of possibilities how to achieve this eg. Core Data, Realm... But the thing is if we decide to implement some part of our app as React Native we'd also need these parts to access stored data and even modify it and save to persistent store.
Can this be achieved? Having one persistent store (SQLite, Realm, something else?) and access it from both Swift code and React Native.

This is extremely easy with React Native in both iOS and Android with Native Modules.
You would build a simple native module in Swift/Obj-C and expose your persistent store:
//RCTMyDataStore.h
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#interface RCTMyDataStore : RCTEventEmitter <RCTBridgeModule>
#end
and
// RCTMyDataStore.m
#import "RCTMyDataStore.h"
#implementation RCTMyDataStore {
}
RCT_EXPORT_MODULE(MyDataStore);
RCT_REMAP_METHOD(getMyData,
getMyData_resolver:(RCTPromiseResolveBlock)resolve
getMyData_rejecter:(RCTPromiseRejectBlock)reject)
{
// get data from my persistent store
if (success) {
// convert to RN passable format (NSDictionary or NSArray)
resolve(myData);
} else {
reject(#"404", #"No data", nil);
}
}
#end
In your React Native code:
import {
NativeModules
} from 'react-native';
const NativeDataStore = NativeModules.MyDataStore; // must match the RCT_EXPORT_MODULE name
NativeDataStore.getMyData()
.then(data => {
// do some stuff
})
For more info on Native Modules and Swift support, you can check out the docs here: https://facebook.github.io/react-native/docs/native-modules-ios.html#exporting-swift

Related

My custom native module is not present inside NativeModules object

So, i wanted to create a native module which will detect, if the app is running on emulator/simulator or an actual device.
Everything works fine on android, but i'm facing issue on iOS.
I have create a AbcModule.h and a AbcModule.m file
#import <React/RCTBridgeModule.h>
#interface AbcModule : NSObject <RCTBridgeModule>
#end
This is AbcModule.h
#import "AbcModule.h"
#implementation AbcModule
RCT_EXPORT_MODULE(GetDetails);
- (BOOL) xyzFunctn {
#if TARGET_IPHONE_SIMULATOR
return YES;
#else
return NO;
#endif
}
RCT_EXPORT_METHOD(xyzFunctn: (RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject) {
resolve self.xyzFunctn;
}
#end
This is AbcModule.m
Here i have followed the react native documentation for implementing the Native Modules.
But i'm consistently facing this error which says
"TypeError null is not an object, evaluating GetDetails.xyzFunctn"
I have went through several solutions and articles but nothing seems to be working here.
Need help guys!
from the docs
If you do not specify a name, the JavaScript module name will match the Objective-C class name, with any "RCT" or "RK" prefixes removed.
so just do not specify any name,
#implementation AbcModule
// To export a module named AbcModule
RCT_EXPORT_MODULE();
#end
in your case it should then be accessible from within JS with
AbcModule
But the documentation is not clear if the Objective-C Class declaration needs to be written with prefixed "RCT" or "RK".. but because both prefixes seem to be valid, you should be able to just use AbcModule without prefix.
In other words, if you want to use GetDetails from within JS you need to name your interface and implementation accordingly
#implementation RCTGetDetails
RCT_EXPORT_MODULE(GetDetails);
// or
// RCT_EXPORT_MODULE();
#end
Okay, if there is someone who is facing this issue and feels like their code should work but it isn't and any solution online not working for you as well.
Try this:
When you create your .h and .m file for header and objective-c or swift file, make sure you do it in Xcode and not from VSCode.
VSCode eventually doesn't adds you .h file in the required resources folder, i have wasted my 2 weeks trying to find out solution for it, but lastly, that was it, yes this is it.
in your .m file, let's say GetDetails is a class of NSObject .swift
you need:
#interface RCT_EXTERN_MODULE(WidgetManager, NSObject)
// method to export
RCT_EXTERN_METHOD(isAuthenticated: (BOOL *)isAuthenticated)
#end
in your GetDetails.swift:
#objc(GetDetails)
class GetDetails: NSObject {
#objc(isAuthenticated:)
func isAuthenticated(_ isAuthenticated: Bool) {
}
}

React Native: Get device name through Native Modules without callback

I would like to get the iOS device name using Native Modules and without using an external library.
According to React Native's documentation, "React Native bridge is asynchronous, so the only way to pass a result to JavaScript is by using callbacks or emitting events". However, the documentation also explains that you can export constants to JavaScript without doing a round-trip from JS to Objective-C.
Is there a way to export a constant from a native module with the device name/model as a value without having to use a callback?
You can create the header file as shown below:
// RCTDeviceInfo.h
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#interface RCTDeviceInfo : NSObject<RCTBridgeModule>
#end
Then to export it you can do :
//RCTDeviceInfo.m
#import "RCTDataLogger.h"
#implementation RCTDeviceInfo
RCT_EXPORT_MODULE(DeviceInfo);
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getName) {
return [[UIDevice currentDevice] name];
}
#end
Then synchronously on the Javascript side you can do the following:
import { NativeModules} from "react-native"
const DeviceInfo = NativeModules.DeviceInfo;
const deviceName = DeviceInfo.getName();
You can read more from the official docs here

Integrations of an iOS component in React Native

I am new to the development of React Native, I know iOS.
Just want to know about few points:
Can we add iOS (swift or objective C) code in a React Native App?
Can we add React Native Views into the existing iOS app?
I have googled and got the examples which point to that 2nd one is quite possible and Instagram did it in edit profile screen.
But I cannot find examples where it's a React Native app and we introduces swift or Objective-C code in between.
Please if anyone knows of any links or examples available for Case 1, please do let me know about it.
2nd question:
When we integrate react native with iOS, it will be through a bridge. Let's say I create an app in Swift, to get react native views in it, we have to go through 2 bridges, one converting Swift to Objective-C and then bridge between Objective-C to React Native. Is that correct? If yes will it be as fast as the native app?
Yes. You can do both of them
1.
https://facebook.github.io/react-native/docs/platform-specific-code.html
2.
https://codeburst.io/integrate-react-native-into-an-existing-app-ios-87c947a16044
https://facebook.github.io/react-native/docs/integration-with-existing-apps.html
Can we add iOS (swift or objective C) code in a React Native App
Yes, I was able to do so:-
I created a React Native project, compiled it and run it in the simulator.
Go to the iOS folder in directory structure in the project and open the .xcodeproj in xcode.
Create an objective c file (MyObjcClass) and make functions which you want to use in React.
MyObjcClass.h
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#interface MyObjcClass : NSObject <RCTBridgeModule>
#end
MyObjcClass.m
#import "MyObjcClass.h"
#implementation MyObjcClass
// tells react bridge to bridge our created class
RCT_EXPORT_MODULE()
- (NSDictionary *)constantsToExport {
return #{#"CreatedBy": #"Type any number and get Square"};
}
RCT_EXPORT_METHOD(squareNumber:(int)number getCallback:(RCTResponseSenderBlock)callback) {
callback(#[[NSNull null], [NSNumber numberWithInt:(number*number)]]);
}
Now we can call these methods in JS.
Below I will show how to call objective c in React.
App.js
import React from 'react';
import { StyleSheet, Text, View, TextInput, Button } from 'react-native';
// to import native code
import {NativeModules} from 'react-native';
var MyObjcClass = NativeModules.MyObjcClass;
export default class App extends React.Component {
state = {
number:0
};
squareMe(num) {
if (num == '') {
return;
}
MyObjcClass.squareNumber(parseInt(num), (error, number) => {
if (error) {
console.error(error);
} else {
this.setState({number: number});
}
})
}
render() {
return (
<View style={styles.container}>
<Text style={styles.spaceBetween}>Objective C inclusion</Text>
<TextInput placeholder="type a number ...." style={styles.input} onChangeText={(text) => this.squareMe(text)}/>
<ListItem placeName={this.state.number}></ListItem>
</View>
);
}
}
yes we can do
import {Platform} from 'react-native';
const majorVersionIOS = parseInt(Platform.Version, 10);
if (majorVersionIOS <= 9) {
console.log('Work around a change in behavior');
}
To bridge an iOS native module into React Native, you can follow along the official instructions: iOS Native Modules.
To paraphrase the important parts:
Open your .xcworkspace file in your ios folder to open XCode
Select File > New > File
Select header file
Name the header and select your project and its tests as the targets
// RCTCalendarModule.h
#import <React/RCTBridgeModule.h>
#interface RCTCalendarModule : NSObject <RCTBridgeModule>
#end
Select File > New > File
Select Objective-C file. Name it the same as the header but with .m instead of .h. Select your project and its tests and targets
// RCTCalendarModule.m
#import "RCTCalendarModule.h"
#implementation RCTCalendarModule
// To export a module named RCTCalendarModule
RCT_EXPORT_MODULE();
#end
In your React Native App or component, import NativeModules and use your new method
import {NativeModules, Button} from 'react-native';
const {CalendarModule} = NativeModules;
const onPress = () => {
CalendarModule.createCalendarEvent('testName', 'testLocation');
};
Note: You will need to keep rebuilding your ios app as you iterate (eg. run yarn ios after making a change to the .m or .h files)
For your second question, you can also add React Native into existing iOS apps. Follow these official instructions: Integration with Existing Apps.

How to go to specific native view controller from react-native code?

I'm a newbie in react-native. I'm adding one feature in react-native to an existing swift application. I presented the RCTRootview from my native view controller. From there when user clicks on back button I have to go to Homepage which is written in swift. How do I communicate from react-native to native application code. Can someone please help me with this scenerio. I stuck at this point from last 2 days. Thanks in advance.
Yes. I found out the answer for this. It is all possible with RCTBridgeModule. This piece of code illustrate how to do that.
#import "CalendarManager.h"
#import <React/RCTLog.h>
#implementation CalendarManager
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
{
RCTLogInfo(#"Pretending to create an event %# at %#", name, location);
}
Now, from your JavaScript file you can call the method like this:
import {NativeModules} from 'react-native';
var CalendarManager = NativeModules.CalendarManager;
CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey');
Please follow the below official link about the concept and how to do it.

How do I save a simple NSString to Firebase in Obj C?

I'm new to Obj-C and having a hard time following the instructions available from Firebase. How do I save a simple NSString to the Firebase database?
I'm trying to save a unique user identifier and then be able to tie a zip code to it. I've made it to this step in the instructions, but my code (below) won't save to Firebase: https://firebase.google.com/docs/database/ios/save-data
#import "ZipCodeVC.h"
#import <FirebaseStorage/FirebaseStorage.h>
#import <FirebaseDatabase/FirebaseDatabase.h>
#interface ZipCodeVC ()
#property FIRDatabaseReference *ref;
#end
#implementation ZipCodeVC
- (void)viewDidLoad {
[super viewDidLoad];
[self.ref setValue:#"Test" forKey:#"Testing 1"];
}
#end
On a similar note, does anyone know of a good Firebase guide for Objective-C apart from what's available from Firebase? Most of the guides I've found are for swift.
First of all, you are creating a variable to a Firebase reference, but never initializing it.
Step 1: Initialize your ref:
self.ref=[[FIRDatabase database]reference];
Step 2: Save to your desired path (Testing 1 in this case)
[[self.ref child:#"Testing 1"] setValue:#"Test"];
You also may need to add Firebase to your App Transport Security Settings (ever since Apple increased their security on HTTP links. To do this, go to your info.plist file, then add a new key called "App Transport Security Settings". Then, add a sub-key called "Allow Arbitrary Loads" and make it a boolean with value YES. Then add a dictionary sub-key named "Exception Domains" and add a string key under that with value: "https://console.firebase.google.com". Now, your app is allowed to load the firebase console. It should look something like this:
Last step:
Modify your read/write rules by going to Database->Rules in your Firebase console. Then, create 2 lines:
".read":true,
".write":true
This allows you to write data to the Firebase console from any client. You should now be all set up to save data to Firebase from iOS.

Resources