Integrations of an iOS component in React Native - ios

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.

Related

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

I can't see any iOS Native Module in JS

I have some experience with React but I'm new to React Native.
I've played around for a while, but I got stuck when I tried to write a basic native module for iOS. I've tried with both Swift and Objective C. (I have some basic experience with Swift, but Objective C is completely new for me)
Some context:
The project is created with react-native-cli 2.0.1
I use XCode 9.1
Here is the .swift class
import Foundation
#objc(Something)
class Something: NSObject {
#objc
func printSomething() -> Void {
print("Something")
}
}
Here is the bridge file
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#interface RCT_EXTERN_MODULE(Something, NSObject)
RCT_EXTERN_METHOD(printSomething)
#end
And the Project-Brigding-Header.h
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import <React/RCTBridgeModule.h>
My App.js file
...
import { NativeModules } from 'react-native';
...
type Props = {};
export default class App extends Component<Props> {
componentDidMount() {
console.log('NativeModules: ', NativeModules);
}
...
}
Here is the problem. The output of console.log() says NativeModules is an empty object:
2018-02-22 18:19:04.590 [info][tid:com.facebook.react.JavaScript] 'NativeModules', {}
2018-02-22 18:19:04.589970+0200 velimo_app_rn[14748:400982] 'NativeModules', {}
I don't understand what I'm doing wrong. I've read pretty much everything I could find only related to the topic but I can't see what I do wrong.
If you have any suggestion, please let me know. Thanks!
The solution was to log the module name console.log(NativeModules.Something), not the whole NativeModules object. It wasn't anything wrong with my setup.
If you made changes to the native iOS code, then you need to rebuild the project by
rerunning npx react-native run-ios and restart the server npx react-native start.
I also relaunched the app in the simulator.

Accessing the same persistent store from Swift and React Native

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

Library not linking with 0.41 versions of react-native

I'm having issues linking libraries to a react-native project even after attempting to link manually multiple different times. I've gone through a ton of "praised" tutorials with no success.
I'm not an expert in Objective-C/iOS-native, so to isolate the issue I decided to create a HelloWorld Library and a HelloWorld react-native project.
Using:
react-native v0.41.2
react-native-cli v2.0.1
react-native-create-library v1.0.4
xcode v8.2.1
I did the following:
react-native-create-library Lib.
react-native init RNLibTest.
"Successfully linking" (Tried both manually and react-native link ...)
Here is the code:
RNLib
// ./ios/RNLib.h
#import <React/RCTBridgeModule.h>
#interface RNLib : NSObject <RCTBridgeModule>
#end
// ./ios/RNLib.m
#import "RNLib.h"
#implementation RNLib
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(helloWorld:(NSString *)world)
{
return [NSString stringWithFormat:#"hello %#", world];
}
#end
// ./index.js
import { NativeModules } from 'react-native';
const { RNLib } = NativeModules;
console.log(RNLib); // undefined
console.log(NativeModules); // Object: RNLib NOT included
export default RNLib;
HelloWorld / RNLibTest
// index.ios.js
import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';
import RNLib from 'react-native-lib'; // I installed RNLib with npm and then "linked".
export default class RNLibTest extends Component {
componentDidMount() {
console.log(RNLib); // undefined
}
render() {
return (
<View>
<Text>Hello World</Text>
<Text>{
RNLib.helloWorld("world")
/* throws error "can't read property helloWorld of undefined" */
}</Text>
</View>
);
}
}
AppRegistry.registerComponent('RNLibTest', () => RNLibTest);
My questions:
If the code is not wrong, could it be the xcode project created by react-create-native-library somehow not working with newer versions of react-native?
Is anyone else having these issues? If so, what did you do to fix it?
If you haven't encountered this issue, are you using the latest version of react-native?
What version are you using of xcode, react-native-cli, etc...?
Did anyone have to downgrade to fix this issue?
UPDATE Feb/22/2017
There is a new release of react-native-create-library (v1.1.0) that supports v0.40+. I tried again and updated the code above, but I'm still seeing the same issue.
Here is a link to the GitHub issue. I also uploaded react-native-lib library and LibTest app to GitHub.
Not Sure Whether react-native-create-library support 0.41 RN But from the code i could say you need to import RCT*h files like <React/RCTBridgeModule.h>
Since this is single fine you can create a RNLib.h File in Xcode and check you would get compile time error
Thanks
I don't know what caused the issue but with react-native 0.42 out, I decided to try again.
Same code, same libraries, same everything BUT react-native 0.42, these were my results:
using react-native link => WORKED.
using manual installation => WORKED.
I'm not sure what happened in 0.41 but it is not happening in 0.42!

How to prevent Screen lock ios with Qt

I want to develop an app in Qt for iOS that contains a map. During the use, the screen lock of the phone should be disabled.
But I can't find any solution how to prevent the screen lock in iOS using Qt.
How can be done that?
You must use the native iOS api. You can compile ObjC++ code directly with the clang compiler in your Qt application.
So you can mix .cpp and .mm (ObjC++) files. QtCreator and qmake support this via the OBJECTIVE_SOURCES keyword.
In a yourclass.mm implementation:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
void YourClass::setTimerDisabled() {
[[UIApplication sharedApplication] setIdleTimerDisabled: YES]
}
yourclass.h:
class YourClass
{
public:
void setTimerDisabled()
}
Now you can call from anywhere in your Qt-app:
YourClass yc;
yc.setTimerDisbabled();
In your project file (.pro), if you only want this file on iOS:
ios {
OBJECTIVE_SOURCES += \
yourclass.mm \
}
And if you only want specified code on a single platform, use preprocessor commands in your source and header files like this:
#if defined(Q_OS_IOS)
// iOs stuff
#elsif defined(Q_OS_ANDROID)
//Android stuff ...
#else
//Other stuff ...
#endif

Resources