I want access to the device name (from UIDevice) with React Native. Is there a good way to do that?
You need to make a Native Modules (iOS). Here are the steps:
Make native iOS component for getting device name
Use it in JS
1. Make Component
// Device.h
#import UIKit;
#import "RCTBridgeModule.h"
#interface Device : NSObject <RCTBridgeModule>
#end
// Device.m
#import "Device.h"
#implementation Device
RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(deviceName:(RCTResponseSenderBlock)callback) {
NSString *deviceName = [[UIDevice currentDevice] name];
callback(#[deviceName]);
}
#end
2. Use it in JS
var Device = require('react-native').NativeModules.Device;
Device.deviceName( (name) => {
console.log(name)
});
Related
I'm following the example posted in the official doc for native module ios. I've set up everything, build it and run the application.
// CAL.h
#import <React/RCTBridgeModule.h>
#interface CAL : NSObject <RCTBridgeModule>
#end
// CAL.m
#import <React/RCTLog.h>
#import "CAL.h"
#implementation CAL
RCT_EXPORT_MODULE(CAL);
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)name location:(NSString *)location)
{
RCTLogInfo(#"Pretending to create an event %# at %#", name, location);
}
#end
But when I check NativeModules from react-native it shows an empty object - {}.
I'm not sure what I'm missing.
Like #chengsam mentioned, when I access CAL directly in the following manner it works.
const { CAL } = NativeModules;
or
NativeModules.CAL
CAL still held the native module while NativeModules directly displayed {}
Trying to get ObjC app project to call Swift function within ObjC static lib..........
My ObjC app project build gets build error for reference to a Swift function that is within an ObjC static lib (.a) that is imported into the app project.
The file Hub_lib-Bridging-Header.h has no code.
OBJ-C APP PROJECT..............................................
ViewController.mm within the ObjC app project...
#import "ViewController.h"
#import "Hub_lib.h"
#import "Hub_lib-Swift.h"
#import "hublib.hpp"
#interface ViewController ()
#end
#implementation ViewController
. . .
- (IBAction)run_simple_central:(id)sender {
[self BLE.start_central];
}
BLE.h within ObjC app project...........
#import <CoreBluetooth/CoreBluetooth.h>
#import "Hub_lib-Swift.h"
#interface BLE: NSObject
//< CBPeripheralManagerDelegate >
#property(strong, nonatomic) CBPeripheralManager* peripheralManager;
#property(strong, nonatomic) CBMutableCharacteristic* transferCharacteristic;
#property(strong, nonatomic) NSData* dataToSend;
#property(nonatomic, readwrite) NSInteger sendDataIndex;
-(void)start_central;
#end /* BLE_h */
BLE.m within app; a wrapper for call to swift..........................
#import "BLE.h"
#import "Hub_lib-Swift.h"
#interface BLE ()
#end
#implementation BLE
-(void)start_central
{
Hub_lib* BLE_central = [Hub_lib new];
[BLE_central centralManager.run_central];
}
made a test project to be able to replicate your errors.
You are close but you need to take care of how your static lib has its internal methods and classes exposed in its header so you can use them elsewhere.
let's begin with the Objective-C Static Library project. Hub_lib.h
#import <Foundation/Foundation.h>
// we want the lib header as clean as possible
// it will then be imported in your project with '#import <Hub_lib/Hub_lib.h>'
// auto-generated swift -> objc bridging header imported here will
// mess it up when imported somewhere else.
// so when using swift->objc bridging place next line in .m file instead
//#import "Hub_lib-Swift.h"
//#class BLE_Central; // pre-declaration of a later fully declared Class.
// as we moved the property into .m file we dont need it here.
#interface Hub_lib : NSObject
// to make this work you would need pre-declaration of BLE_Central, see above interface
//#property BLE_Central *ble; // placed in .m interface extension instead.
-(void)run_central;
#end
static lib counterpart / implementation Hub_lib.m
#import "Hub_lib.h"
#import "Hub_lib-Swift.h"
#interface Hub_lib ()
#property BLE_Central *ble_central;
#end;
#implementation Hub_lib
-(instancetype)init {
if (!(self=[super init])) return nil;
_ble_central = [[BLE_Central alloc] init];
return self;
}
-(void)run_central {
[_ble_central run_central];
}
#end
notice BLE_Central property is placed in the class interface extension and when you want to use swift module stuff that exposes back to objc you need to declare the auto-generated bridge somewhere (best done in .m file #import "Hub_lib-Swift.h")
your BLE_central.swift with its protocol method implementation
import Foundation
import UIKit
import CoreBluetooth
import os
var centralManager: CBCentralManager = CBCentralManager()
class BLE_Central: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
os_log("centralManagerDidUpdateState")
}
var discoveredPeripheral: CBPeripheral?
var transferCharacteristic: CBCharacteristic?
var writeIterationsComplete = 0
var connectionIterationsComplete = 0
let defaultIterations = 5 // change this value based on test usecase
var data = Data()
// as you figured out before we need to expose to #objc
#objc public func run_central()
{
os_log("run_central")
// out-commented for testing purposes
//mobile_sys_hub_lib.centralManager = CBCentralManager(delegate: self, queue: nil, options: [CBCentralManagerOptionShowPowerAlertKey: true])
os_log("Scanning started")
}
}
As long no extra code from objc is used in swift inside the static lib, the
Hub_lib-Bridging-Header.h is empty
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
Next let's see how to import your static lib in your "sim backend UI" Objective-C Project app.
Goto "sim backend UI" App Target settings > General > Framework, Libraries, and.. > hit the + button and search for your compiled libHub_lib.a file. > select it > hit ok. Should be very much in your framework list by now.
Yes, thats not enough! You have to declare its header in your app project somewhere. Where exactly is up to you. Instead of implementing it multiple times we do the following in BLE.h
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
//#import "Hub_lib-Swift.h" // no no no no
#import <Hub_lib/Hub_lib.h> // much better. test-compile once if it is crying
NS_ASSUME_NONNULL_BEGIN
#interface BLE: NSObject
// <CBPeripheralManagerDelegate> // "//<Protocol>" will confuse doxygen
#property (strong, nonatomic) CBPeripheralManager* peripheralManager;
#property (strong, nonatomic) CBMutableCharacteristic* transferCharacteristic;
#property (strong, nonatomic) NSData* dataToSend;
#property (nonatomic, readwrite) NSInteger sendDataIndex;
-(void)start_central;
#end /* BLE_h */
NS_ASSUME_NONNULL_END
counterpart BLE.m
#import "BLE.h"
#implementation BLE
-(void)start_central
{
NSLog(#"invoked BLE start_central");
Hub_lib *Hub_central = [Hub_lib new];
[Hub_central run_central];
}
#end
Your ViewController.m or .mm makes use of BLE.h with its already imported static lib header
#import "ViewController.h"
#import "BLE.h"
#interface ViewController ()
#property (nonatomic) BLE *ble;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.frame = CGRectMake(100, 100, 200, 50);
[btn setTitle:#"run simple central" forState:(UIControlStateNormal)];
[btn setTitleColor:UIColor.greenColor forState:(UIControlStateNormal)];
btn.layer.backgroundColor = UIColor.orangeColor.CGColor;
btn.layer.cornerRadius = 5.0f;
[self.view addSubview:btn];
[btn addTarget:self action:#selector(run_simple_central:) forControlEvents:(UIControlEventTouchUpInside)];
}
- (IBAction)run_simple_central:(id)sender {
// BLE needs to be allocated to take effect.
if (!_ble) _ble = [[BLE alloc] init];
// testing.. should log "run_central" + "Scanning started"
[self.ble start_central];
}
#end
Made a testButton so you can see if the implementation invokes what you expect. Compile!
And? Aoutsch! Does not work. What happened?
If your App is a plain Objective-C project it doesn't know about swift yet and will complain in a weirdo way, possibly via something like
Link: Could not find or use auto-linked library 'swiftCoreImage'
Undefined symbol: value witness table for Builtin.UnknownObject*
Solution: Most easy way is to create a swift file in your app project and allow Xcode to make a bridging header for you. (Alternatively change project settings, search for "bridge" and go step by step thru the properties)
The swift file does not have to have special content.
//
// MakeProjectSwiftCompatible.swift
//
import Foundation
Compile again. now it should work because the partly implemented swift module from within your static lib can properly work when your Objc-App-Project is able to work with swift stuff.
Edit as you asked to work with Objective-C++/C++ in your static library things change a little bit.. so here some additional example code to proof it.
In Hub_lib project (targeting your "framework") add some files which will keep some random testing c++ code
//HubCPP.h
#import <Foundation/Foundation.h>
#include <vector>
NS_ASSUME_NONNULL_BEGIN
class SomeCPPClass
{
public:
SomeCPPClass(id<NSObject> obj, size_t size);
~SomeCPPClass();
id<NSObject> getBuffer() { return buffers[bufferIdx]; }
unsigned int getCurrentIdx();
private:
std::vector <id <NSObject>> buffers;
unsigned int bufferIdx;
bool isReady;
};
NS_ASSUME_NONNULL_END
To make Xcode know that you work with C++ you need to have implementation file ending with .mm and also need to change HubCpp.h "Identity and Type (right Xcode panel while file selected)" to C++ Header
// HubCpp.mm
#import "HubCPP.h"
SomeCPPClass::SomeCPPClass (id<NSObject> obj, size_t size) :
bufferIdx (0),
isReady(false)
{
uint8_t ringSize = 255;
assert (ringSize > 0);
for (uint8_t i = 0; i < ringSize; i++)
{
//buffers.push_back ();
bufferIdx = (unsigned int)size;
}
}
SomeCPPClass::~SomeCPPClass() {
// cleanup allocated stuff here.
}
unsigned int SomeCPPClass::getCurrentIdx() {
return bufferIdx;
}
Rename Hub_lib.m to .mm and change its import rules accordingly to the following ..
#import "Hub_lib.h"
#import <CoreBluetooth/CoreBluetooth.h> //needed because the -Swift.h bridge will cry in the next line
#import "Hub_lib-Swift.h"
#import "HubCPP.h"
lets change the proofing method in Hub_lib.mm so it really uses C++
-(void)run_central {
[_ble_central run_central];
SomeCPPClass *cpp = new SomeCPPClass(#"justSomeNSStringObject",2);
unsigned int idx = cpp->getCurrentIdx();
NSLog(#"objectiveCplusplus testIdx = %u", idx);
}
Compile Hub_lib (scheme). It should work by now and also accept the use of #import <vector>.
If this works go on and change your Objc-Project-App.
Switch your compile Scheme to target your Objc-App.
Change file name BLE.m to BLE.mm (makes it a Objective C++ Source)
Change file name BLE.h to BLE.hh (makes it a C++ header)
Change in BLE.mm #import "BLE.h to #import "BLE.hh
in ViewController.m kick out the line #import "BLE.h" and replace it into ViewController.h instead as #import "BLE.hh"
(In general its much easier to keep your compiler informed what language to expect in implementation when you place import headers in header files.)
Compile. Thats it! Your Objective-C++ static lib should properly work at this point.
Edit
You can find a ready made workspace for Xcode here...github: combine cpp swift and objective-c in static lib
Solution from StackO user: Asperi
Emptied top folder
Created workspace at top folder
1.1 Copied clean app and lib to top folder
Add ObjC lib .xcodeproj to workspace using Xcode > File > Add files ...
Add ObjC app .xcodeproj to workspace
Added dependency of sim_backend_UI to lib via workspace
a. app proj > General tab > Frameworks, Libs.. > +
b. Select lib .a
c. Add.
Add Some.swift (any swift file you want) to sim_backend_UI, just for the purpose Xcode add required system swift dynamic libraries (which will be needed for swift part in static library as well)... and confirm creating bridge in appeared dialog
a. new file > Swift > Some.swift
b. Create Bridging Header
c. Added to Some.swift ...
import Foundation
struct Some{}
Set Xcode active scheme to app and target device
Build
"succeeded"
I'm doing a Tweak and i use Flex to edit some Obj-C but one of these i cant edit so, i think if i do a Tweak with MSHook can resolve this, BUT NO idk how to write correctly i'm new on this, i want to disable "shootCooldown" but idk if is posible, so this is my code on Tweak.x
#import <substrate.h>
#import <Foundation/Foundation.h>
#interface ControlsWidget : NSObject {
NSString *_shootCooldown;
}
#end
NSString *_shootCooldown;
%hook ControlsWiget
{
shootCooldown = MSHookIvar<BOOL>(self, "_someBOOL");
}
%end
Setup:
react-native v0.41.2
react-native-cli v2.0.1
xcode v8.2.1
node v6.9.5
I started using RN v0.41.2 and found that v0.40 introduced a namespace breaking change stating that all react imports should be prepended with React/.
But the documentation shows otherwise.
So, is doing this the only thing that I have to do:
// RNLib.h
#import "RCTBridgeModule.h"
#interface RNLib : NSObject <RCTBridgeModule>
#end
to
// RNLib.h
#import <React/RCTBridgeModule.h>
#interface RNLib : NSObject <RCTBridgeModule>
#end
Or do I have to do it for my imports as well:
// RNLib.m
#import "RNLib.h"
#implementation RNLib
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(helloWorld:(NSString *)world)
{
return [NSString stringWithFormat:#"hello %#", world];
}
#end
to
// RNLib.m
#import <React/RNLib.h>
#implementation RNLib
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(helloWorld:(NSString *)world)
{
return [NSString stringWithFormat:#"hello %#", world];
}
#end
I'm currently unable to create a library and link it correctly (I've tried multiple things).
// somthing.m
#import "something.h"
This above line refers to something.h file which is present in same directory of the implementation file.
Only Modules from the React should be prepended with "React/RCTWhatever.h".
This has effective change in Header Search Paths of Xcode when you are linking the Native Libraries.
Thanks
I am using cocos2d 3.0.
In AppDelegate class I have implemented admob and it works fine, but it is always on the screen. But I want admob to be hidden during the main scene and to appear when it is game over.
In AppDelegate.h I have
#import <UIKit/UIKit.h>
#import "cocos2d.h"
#import "GADBannerView.h"
typedef enum _bannerType
{
kBanner_Portrait_Top,
kBanner_Portrait_Bottom,
kBanner_Landscape_Top,
kBanner_Landscape_Bottom,
}CocosBannerType;
#define BANNER_TYPE kBanner_Portrait_Top
#interface AppController : CCAppDelegate
{
CocosBannerType mBannerType;
GADBannerView *mBannerView;
float on_x, on_y, off_x, off_y;
}
-(void)hideBannerView;
-(void)showBannerView;
In MainScene class I've tried to write
mBannerView.hidden = YES;
but it is said that mBannerView is undeclared identifier.
I guess i should somehow use -(void) hideBannerView, but I don't know how.
Could you please tell me what should I do to hide admob on certain scenes.
You can move banner up and down to hide.
AppController *app = (AppController*)[UIApplication sharedApplication].delegate;
[app hideBannerView];
Here is Full Source: Cocos2d v3 Admob Sample