React Native: Get device name through Native Modules without callback - ios

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

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) {
}
}

RCTBridge is Always Nil

I have been using React Native for a mobile app project for over a year now. I have a native component to bridge the BLE stack to the React Native portion of the app. Recently I upgraded to version 9.1 of XCode and I cannot get the React-Native Bridge to work within the iOS version. The RCTBridge is always nil so I can never use the eventDispatcher(). Here is my setup:
I have a native Swift component which I integrate into the app via a bridgin header. The origanization looks like this:
BLEScanner.swift (This is the native component)
BluetoothModuleBridge.m
Module-Practive-Bridging-Header.h (The bridging header)
Relevant code snippets from each file:
BLEScanner.swift
import Foundation
#objc(BLEScanner)
class BLEScanner: NSObject {
//....
var bridge: RCTBridge! // THIS IS ALWAYS NIL
//....
#objc func requestBluetoothState() -> Void {
print("REQUEST BLE STATE")
let ret = [
"enabled" : true
]
//THIS LINE WILL FAIL BECAUSE bridge IS NIL
self.bridge.eventDispatcher().sendDeviceEvent(withName: "BluetoothStateEvent", body: ret)
}
}
BluetoothModuleBridge.m
#import <React/RCTBridgeModule.h>
#interface RCT_EXTERN_MODULE(BLEScanner, NSObject)
RCT_EXTERN_METHOD(requestBluetoothState)
#end
Module-Practive-Bridging-Header.h
// BluetoothModule-Bridging-Header.h
#import <React/RCTBridge.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTRootView.h>
#import <React/RCTUtils.h>
#import <React/RCTConvert.h>
#import "AppDelegate.h"
#import "BugsnagReactNative/BugsnagReactNative.h"
#import "nokeLockSDK.h"
#import "nokeServerSDK.h"
#import "TI_aes_128.h"
What I have Tried
Updated React Native from 0.36 to 0.50.3
Tried running on multiple devices
Tried on older version of XCode
Tried compiling on different machine
Compared to a similar app that works and uses this same design.
I am very confused as to why the RCTBridge is returning as nil. It seems odd to me that an XCode update would cause this, however, it is the only change made.
Can anyone point me in the right direction in debugging this issue?
I am using XCode 9.1 and React Native 0.50.3
You do not have to subclass RCTEventEmitter. Just add the #objc attribute. So the variable should be #objc var bridge: RCTBridge!
Do you have your own initial method? If so try remove it. After my test, it has no problem.
And it is recommended to Subclass RCTEventEmitter instead.
If you upgraded to 9.1 and also React Native to 50.x from 30.x at the same time, you could have wrong imports, as that is something that changed around version 40.
It should be
#import <React/RCTBridgeModule.h>
If you don't want to subclass RCTEventEmitter, implement protocol RCTBridgeModule in your BLEScanner.
That will solve the problem.

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

React Native App Stuck On Splash Screen

I am trying to learn how to build a react-native module. I followed a tutorial and I am getting stuck on the splash screen. I also get this error when I try to run my app:
Thread 1: signal SIGABRT
I have not modified any of the code in index.ios.js but I have created and two files:
GifMaker.h
#import <Foundation/Foundation.h>
#import "React/RCTBridgeModule.h"
#interface GifMaker : NSObject
#end
GifMaker.m
#import "GifMaker.h"
#import "React/RCTLog.h"
#implementation GifMaker
// This RCT (React) "macro" exposes the current module to JavaScript
RCT_EXPORT_MODULE();
// We must explicitly expose methods otherwise JavaScript can't access anything
RCT_EXPORT_METHOD(get)
{
RCTLogInfo(#"Hello There!");
}
#end
I found a solution, I used react-native-create-library to create the .h and .m files and then just copied those into my project.

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