Access JSCall Invoker via the bridge in React Native Module - react-native

I am trying to access the jsCallInvoker method which is a reference to the JS thread on the react native bridge, but in xcode i dont see the reference to the method, i have forked the react-native-mmkv library but havent got access to the above variable. I would want to know if i need to add any more header files, or is there any other way i can get access to the JSinvoker method
I am using React version 0.66 with hermes enabled
#import "MmkvModule.h"
#import "JSIUtils.h"
#import <React/RCTBridge+Private.h>
#import <ReactCommon/CallInvoker.h>
#import <React/RCTUtils.h>
#import <jsi/jsi.h>
#import <MMKV/MMKV.h>
#import "MmkvHostObject.h"
using namespace facebook;
#implementation MmkvModule
RCT_EXPORT_MODULE(MMKV)
+ (NSString*)getPropertyAsStringOrNilFromObject:(jsi::Object&)object
propertyName:(std::string)propertyName
runtime:(jsi::Runtime&)runtime
{
jsi::Value value = object.getProperty(runtime, propertyName.c_str());
std::string string = value.isString() ? value.asString(runtime).utf8(runtime) : "";
return string.length() > 0 ? [NSString stringWithUTF8String:string.c_str()] : nil;
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install:(nullable NSString*)storageDirectory)
{
NSLog(#"Installing global.mmkvCreateNewInstance...");
//RCTBridge
RCTBridge* bridge = [RCTBridge currentBridge]; /// THIS VARIABLE doesnt have access to js call invoker
RCTCxxBridge* cxxBridge = (RCTCxxBridge*)bridge;
if (cxxBridge == nil) {
return #false;
}
using namespace facebook;
auto jsiRuntime = (jsi::Runtime*) cxxBridge.runtime;
if (jsiRuntime == nil) {
return #false;
}
auto& runtime = *jsiRuntime;
RCTUnsafeExecuteOnMainQueueSync(^{
[MMKV initializeMMKV:storageDirectory];
});
// MMKV.createNewInstance()
auto mmkvCreateNewInstance = jsi::Function::createFromHostFunction(runtime,
jsi::PropNameID::forAscii(runtime, "mmkvCreateNewInstance"),
1,
[](jsi::Runtime& runtime,
const jsi::Value& thisValue,
const jsi::Value* arguments,
size_t count) -> jsi::Value {
if (count != 1) {
throw jsi::JSError(runtime, "MMKV.createNewInstance(..) expects one argument (object)!");
}
jsi::Object config = arguments[0].asObject(runtime);
NSString* instanceId = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"id" runtime:runtime];
NSString* path = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"path" runtime:runtime];
NSString* encryptionKey = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"encryptionKey" runtime:runtime];
auto instance = std::make_shared<MmkvHostObject>(instanceId, path, encryptionKey);
return jsi::Object::createFromHostObject(runtime, instance);
});
runtime.global().setProperty(runtime, "mmkvCreateNewInstance", std::move(mmkvCreateNewInstance));
NSLog(#"Installed global.mmkvCreateNewInstance!");
return #true;
}
#end

You need to import
#import <React/RCTBridge+Private.h>
#import <React/RCTUtils.h>
#import <ReactCommon/RCTTurboModule.h>
#import <jsi/jsi.h>
Also Your Podspec file needs to have the following dependencies
s.dependency "React-Core"
s.dependency "React"
s.dependency "React-callinvoker"
Then do pod install

Related

Formatting a disk in macOS programmatically using DiskManagement.framework

I have a task to implement disk formatting functionality in my code.
I am against the use of command line wrappers (e.g. diskutil), as they are slow and unreliable.
I'm importing this private framework: /System/Library/PrivateFrameworks/DiskManagement.framework
And the following headers: DMManager.h, DMEraseDisk.h, DMFilesystem.h (GitHub Repo)
I have almost everything ready, but there is one problem that I can not overcome:
Calling the eraseDisk method in DMEraseDisk freezes the application.
At the same time, the disk is formatted successfully, I just need to mount it manually.
#import <Foundation/Foundation.h>
#import <DiskArbitration/DiskArbitration.h>
#import "DiskManagement/DMManager.h"
#import "DiskManagement/DMEraseDisk.h"
#import "DiskManagement/DMFilesystem.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
/* From the public DiskArbitration.h */
DASessionRef diskSession = DASessionCreate(nil);
DADiskRef currentDisk = DADiskCreateFromBSDName(NULL, diskSession, "disk9s1");
/* From DiskManagement.framework private headers (DMManager.h, DMEraseDisk.h, DMFilesystem.h) */
DMManager *dmManager = [DMManager sharedManager];
DMEraseDisk *diskEraser = [[DMEraseDisk alloc] initWithManager:dmManager];
/* Getting available file systems for a given device */
NSArray *availableFilesystems = [DMEraseDisk eraseTypesForDisk:currentDisk];
printf("Available File Systems for this device:\n");
for (DMFilesystem *availableFilesystem in availableFilesystems) {
printf("[Type:] %s\n", [[availableFilesystem filesystemType] UTF8String]);
printf("[Personality:] %s\n", [[availableFilesystem filesystemPersonality] UTF8String]);
printf("---\n");
}
/* (Type: msdos, Personality: MS-DOS FAT32) */
DMFilesystem *selectedFilesystem = [availableFilesystems objectAtIndex:2];
/*
(Formatting this device to MS-DOS FAT32)
Formats successfully, but stops here
and the code after this function is not executed further
*/
[diskEraser
eraseDisk: currentDisk
synchronous: YES // Won't work if set to NO (even with CFRunLoopRun())
filesystem: selectedFilesystem
bootable: YES
name: #"RESOPHIE"
doNewfs: YES
doBooterCleanup: NO
];
printf("I will never show up :(\n");
}
return 0;
}
How can I make the code continue to execute after calling eraseDisk method?

JNI header missing in Objective-C

I have a file.c in my project which has #include <jni.h> header file. What is the process to include this header file in project or macOS?
Let's say you have following code
#include "jni.h"
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
JNIEnv *env;
JavaVM *jvm;
JavaVMInitArgs vm_args;
JavaVMOption options[3];
options[0].optionString = "-Djava.class.path=_HERE_GOES_LOCATION_OF_JNICOOKBOK_/jnicookbook/recipeNo051/target";
vm_args.options = options;
vm_args.ignoreUnrecognized = 0;
vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = 1;
int status = JNI_CreateJavaVM (&jvm, (void **) &env, &vm_args);
if (status < 0 || !env) {
printf ("Error - JVM creation failed\n");
return 1;
}
jclass cls_Main = (*env)->FindClass (env, "recipeNo051/Main");
jmethodID method_displayMessage = (*env)->GetStaticMethodID (env, cls_Main, "displayMessage", "()V");
(*env)->CallStaticVoidMethod(env, cls_Main, method_displayMessage);
(*jvm)->DestroyJavaVM( jvm );
}
return 0;
}
in order to run it you will need
location of libjvm.dylib
location of headers
location of compiled Java classes that are called from main.m
Let's start with libs and headers. You have to make sure that following paths are searched for includes (note that I am using jdk-11.0.4):
/Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home/include
/Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home/include/darwin/
You have to make sure that following path is added to Library Search Path and to Runpath Search Paths
/Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home/lib/server
You should have settings like that:
Make sure you are linking your code with libjvm.dylib. Add it inside Build Phases
where you can specify it's location by choosing Add Other...
Run your code, but! Make sure to ignore SIGSEGV before calling method JNI_CreateJavaVM. You can ignore it inside lldb console
(lldb) process handle --pass true --stop false SIGSEGV
After you continue, you can see your JVM instance calling classes from the recipeNo051.
Source code of class: recipeNo051/Main can be found here: https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo051
Update
step by step instructions: http://www.owsiak.org/running-jni-based-code-inside-xcode/
video tutorial: https://youtu.be/WEA-3uI7Y18

Determining IP Address from URL in iOS

I need to get the IP address of a CDN from it's URL in an iOS app. From a long stack search, i've determined a method for doing this with the following:
struct hostent *host_entry = gethostbyname("stackoverflow.com");
char *buff;
buff = inet_ntoa(*((struct in_addr *)host_entry->h_addr_list[0]));
// buff is now equal to the IP of the stackoverflow.com server
However, when using this code snippet, my app fails to compile and presents this warning: "dereferencing pointer to incomplete type"
I have no knowledge of structs and I do not know how to fix this. Any suggestions?
I also tried:
#include <ifaddrs.h>
#include <arpa/inet.h>
But the result is the same warning.
Here is a Swift 3.1 version of converting a URL hostname to IP address.
import Foundation
private func urlToIP(_ url:URL) -> String? {
guard let hostname = url.host else {
return nil
}
guard let host = hostname.withCString({gethostbyname($0)}) else {
return nil
}
guard host.pointee.h_length > 0 else {
return nil
}
var addr = in_addr()
memcpy(&addr.s_addr, host.pointee.h_addr_list[0], Int(host.pointee.h_length))
guard let remoteIPAsC = inet_ntoa(addr) else {
return nil
}
return String.init(cString: remoteIPAsC)
}
I had no problems compiling that code with the following includes:
#import <netdb.h>
#include <arpa/inet.h>
Maybe this function will work?
#import <netdb.h>
#include <arpa/inet.h>
- (NSString*)lookupHostIPAddressForURL:(NSURL*)url
{
// Ask the unix subsytem to query the DNS
struct hostent *remoteHostEnt = gethostbyname([[url host] UTF8String]);
// Get address info from host entry
struct in_addr *remoteInAddr = (struct in_addr *) remoteHostEnt->h_addr_list[0];
// Convert numeric addr to ASCII string
char *sRemoteInAddr = inet_ntoa(*remoteInAddr);
// hostIP
NSString* hostIP = [NSString stringWithUTF8String:sRemoteInAddr];
return hostIP;
}

iOS - how to call a C function?

I would like to use this function to help monitor memory:
void print_free_memory ()
{
mach_port_t host_port;
mach_msg_type_number_t host_size;
vm_size_t pagesize;
host_port = mach_host_self();
host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
host_page_size(host_port, &pagesize);
vm_statistics_data_t vm_stat;
if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) != KERN_SUCCESS)
NSLog(#"Failed to fetch vm statistics");
/* Stats in bytes */
natural_t mem_used = (vm_stat.active_count +
vm_stat.inactive_count +
vm_stat.wire_count) * pagesize;
natural_t mem_free = vm_stat.free_count * pagesize;
natural_t mem_total = mem_used + mem_free;
NSLog(#"used: %u free: %u total: %u", mem_used, mem_free, mem_total);
}
A. Where do I put this function in my Xcode project?
B. How do I call it? Obviously I'd like to set up to continuously monitor memory.
A. Where do I put this function in my Xcode project?
Put the definition in a separate .c file, and a declaration in a separate header file.
PrintFreeMem.h
extern void print_free_memory();
PrintFreeMem.c
#include "PrintFreeMem.h"
void print_free_memory() {
// Your implementation
}
B. How do I call it?
You can call it the way you call regular C functions, after including its header file:
#include "PrintFreeMem.h"
-(void)myMethod {
...
print_free_memory();
}
You can do the declaration in the header file and write this function in the implementation file or you can simply put the function in the implementation file but then function can be called only from the lines below
print_free_memory ();
Hope this works

AudioFileOpen not opening with read/write permissions

I am trying to programmatically optimize AAC files (.m4a) that were created by software other than iTunes or afconvert using AudioFileOptimize().
However, when I attempt to do an AudioFileOpen with read/write permission and it gives me an error. I can only open with read permissions even if I manually set the POSIX permissions to 0666 (r/w for everyone.)
I'm using the AudioFileOpenUrl method described here and get back 'prm?' (kAudioFilePermissionsError).
Here is the code that is throwing the error:
#import <Cocoa/Cocoa.h>
#import <CoreFoundation/CoreFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import "CAXException.h"
int main(int argc, const char * argv[])
{
int result = 0;
try {
//optimize the output file:
AudioFileID outfile;
NSURL *outputFileURL = [NSURL fileURLWithPath:#"/DIR/PATH TO.m4a"];
OSStatus err = AudioFileOpenURL((__bridge CFURLRef)outputFileURL, kAudioFileReadWritePermission, 0, &outfile);
XThrowIfError(err, "AudioFileOpenURL");
err = AudioFileOptimize(outfile); //Optimize the file
XThrowIfError(err, "AudioFileOptimize");
err = AudioFileClose(outfile);
XThrowIfError(err, "AudioFileClose");
} catch (CAXException e) {
char str[32];
printf ("CAXException thrown from CoreAudioConverter.mm. : %s, %s\n", e.FormatError(str), e.mOperation);
result = 1;
} catch (...) {
result = 1;
}
return result;
}
This outputs:
CAXException thrown from CoreAudioConverter.mm. : 'prm?', AudioFileOpenURL
If anyone can help, that would be AWESOME!
Side-note, has anyone done any work programmatically adding streaming hints to aac files?
Thanks!
AudioFile Services will not allow Write access to certain files:
There is however a limitation when working with MPEG-4 file types which include; .mp4 (kAudioFileMPEG4Type), .m4a (kAudioFileM4AType), .3g2 (kAudioFile3GP2Type) and .3gp (kAudioFile3GPType).
AudioFile does not currently support writing to existing files of these types.
See:
http://developer.apple.com/library/mac/#qa/qa1676/_index.html