React Native - Wrapping native objects created in native modules - react-native

I'm interested in wrapping some C++ libraries as react-native modules but I'm hitting a bit of a conceptual wall. Very new to this stuff so bear with me!
I want to wrap something like the AudioProcessorGraph functionality of Juce https://juce.com/doc/classAudioProcessorGraph_1_1AudioGraphIOProcessor
However a big component of the api is connecting audio node objects to each other to form an audio processing graph. You can imagine something very similar to the web audio api:
const audioCtx = new AudioContext();
const oscillator = new OscillatorNode(audioCtx);
const gainNode = new GainNode(audioCtx);
oscillator.connect(gainNode).connect(audioCtx.destination);
The problem I'm seeing, before I even write a single line of code, is that I don't see a way with the RCT_EXPORT_METHOD macro to pass an instance of a native object as an argument to a method call of another native object. https://nodejs.org/api/addons.html#addons_wrapping_c_objects I've done similar things with native node addons using the ObjectWrap functionality. Is there anyway to accomplish something similar with react-native?

RCT_EXPORT_METHOD is used to export a function to the JS side in IOS. The caveat here is that the arguments you pass via JS to Native or from Native to JS should be serializable. This is because the communication happens via the RN Bridge in async manner.
This is what I would do in your case. Lets take the example:
Lets say you have a function in native module
//Initialise a list to store audioContexts
ArrayList<AudioContext> audioCtxList = new ArrayList<AudioContext>();
#ReactMethod
public void createAudioContext(Callback cb){
AudioContext audioCtx = new AudioContext();
audioCtxList.add(audioCtx);
cb.invoke(//...index of the newly created audioCtx)
}
Now in the JS side you have a reference that u can use to talk to native module
so next function would look something like
#ReactMethod
public void createOscillator(int audioCtxId){
AudioCtx actx = // Get the audioContext from the list using the audioCtxId
const oscillator = new OscillatorNode(audioCtx);
const gainNode = new GainNode(audioCtx);
oscillator.connect(gainNode).connect(audioCtx.destination);
}
As a result you would not need to export any native object to JS side and you can accomplish the functionality u need too.

Related

Return non reactive object from setup function

I am using the new Nuxt3 composable useAsyncData to fetch a large csv file.
In the setup function I use the useAsyncData to pull the data ( d3.csv is a sort of fetch function)
const { data } = await useAsyncData(() =>
d3.csv(url)
)
Then I return the data from the setup function. I use it in the other methods of the component (which is written in the traditional Vue options API).
When I observe the data object in the chrome dev tools, it is a ref or a reactive proxy. The thing is that I don't want to have such a large reactive object, because it is not going to change.
How can I return the raw object instead of the reactive version? Is it possible?
Thanks!

Handlebars with Assemble build returning "not an own property of its parent"

I am experiencing the dreaded not an "own property" of its parent issue when attempting to build my Handlebars project.
I have been down the rabbit hole and seen the many explanations of using #handlebars/allow-prototype-access to allow the issue to be bypassed, however it seems the project does not use a standard implementation of Handlebars...
It seems I am using something called engine-handlebars
Where I would expect to implement that allow-prototype-access change, I see the following:
app.pages('./source/pages/**/*.hbs');
app.engine('hbi', require('engine-handlebars'));
I can't fathom how I am supposed to implement the prototype access with this setup...
It seems, after a bit of trial and error, commenting lines out as I go, that the line app.pages('./source/pages/**/*.hbs'); is actually causing the issue...
When I run the project with this line in, I get the error:
Handlebars: Access has been denied to resolve the property "path" because it is not an "own property" of its parent.
You can add a runtime option to disable the check or this warning:
See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details
[10:54:49] ERROR - undefined: Cannot read property 'substring' of undefined
The plugin #handlebars/allow-prototype-access works by modifying the Handlebars instance.
const _Handlebars = require('handlebars');
const { allowInsecurePrototypeAccess } = require('#handlebars/allow-prototype-access');
const Handlebars = allowInsecurePrototypeAccess(_Handlebars);
Note that allowInsecurePrototypeAccess does not modify the instance in place, but creates an isolated instance via Handlebars.create() so you must use its return value.
In your case, engine-handlebars exposes the Handlebars instance in different ways depending on what version you are using.
Based on your code you provided, my guess is you are using <1.0.0, but I'll provide methods for adjusting this for all its versions.
engine-handlebars#<0.6.0
Unfortunately these versions don't expose Handlebars in any way, so if you are using this version I recommend upgrading engine-handlebars to a later version.
engine-handlebars#>=0.6.0 <1.0.0
Version 0.6.0 exposed Handlebars as a property on the exported engine function. This is then referenced throughout the library via this.Handlebars.
You can then change this before setting the app.engine() and it should work.
const _Handlebars = require('handlebars');
const { allowInsecurePrototypeAccess } = require('#handlebars/allow-prototype-access');
const engine = require('engine-handlebars');
// elsewhere...
// const app = ...
// Do this *before* setting app.engine
const insecureHandlebars = allowInsecurePrototypeAccess(_Handlebars);
engine.Handlebars = insecureHandlebars;
app.engine('hbi', engine);
engine-handlebars#>=1.0.0
For version 1.0.0 and beyond, you must pass the Handlebars instance yourself.
const Handlebars = require('handlebars');
const engine = require('engine-handlebars')(Handlebars);
Thus you don't need to set anything on engine, you just pass in the modified instance when you need it.
const _Handlebars = require('handlebars');
const { allowInsecurePrototypeAccess } = require('#handlebars/allow-prototype-access');
// elsewhere...
// const app = ...
// Do this *before* setting app.engine
const insecureHandlebars = allowInsecurePrototypeAccess(_Handlebars);
const engine = require('engine-handlebars')(insecureHandlebars);
app.engine('hbi', engine);

Extend Office JavaScript API with own Browser Control

I'm trying to write a VSTO-Add-In with a System.Windows.Forms.WebBrowser-Control enabling something similar to the Office-JS-Add-In model.
The WebBrowser-control would show some HTML/JS-Page and be able to call C#-functions in the VSTO-Add-In from JavaScript via window.external and the ObjectForScripting-property of the WebBrowser-object.
That is in JS the call would be
window.external.DoFancyStuffToMyDocument(withTheseParams)
while there had to be some
class MyFunctionProxy() {
public void DoFancyStuffToMyDocument(string theParam) {
//code here
}
}
in the C#-Code an this would be attached to the WebBrowser
myWebBrowser.ObjectForScripting = new MyFunctionProxy();
So far so good. Now comes the catch. I want my HTML/JS-Code be able to also utilize the office.js code and functions like
Word.run(function (context) {
var thisDocument = context.document;
var range = thisDocument.getSelection();
range.insertText('"Hitch your wagon to a star."\n', Word.InsertLocation.replace);
//...
}
Does anyone see a way of getting this to work?
My initial guess was that the OfficeJS-taskpane-add-ins in Word on-prem use some some similar methode as above with a class derived from WebBrowser and the appropriate ObjectForScripting. This would then suggest that there must be a (hopefully accessible) class which is assigned to the ObjectForScripting-property handling the function calls from office.js. Then I could proxy this ObjectForScripting-class and add my own functions like 'DoFancyStuffToMyDocument()'.

Global variables objects React-Native

I have one class ContentManager on android objects and global variables ContentManager style, the aim is to create this object from one time only, you can get set properties for it anywhere in the app, now declared on React native the declaration is this? the picture below is me java code on android. Help!!!!!!!
code in java
code in java
create global.js
module.exports = {
// your global variable
},
};
Then require it at the top in your file
GLOBAL = require('../global');
for access
GLOBAL.your_variable_name

Can't get SignalR client events published with Aurelia Event Aggregator

I have a single page app based on Aurelia and I'm trying to get it to work with an existing SignalR backend. I've downloaded the SignalR javascript client and integrated it with the Aurelia app manually (i.e. I'm not using a proxy file). I'm able to connect to the SignalR hub and see the arrvive messages in the console.... so far so good. Now, I'm trying to use the Aurelia Event Aggregator so that when a new hub message arrives an event is fired and any components of the app subscribed to that particular event will do some work. The issue is that the SignalR event callback doesn't seem to be able to access the Event Aggregator object. Here's the code to illustrate the issue:
//Import statements omitted for brevity
#inject (EventAggregator)
export class MyService{
constructor(eventAggregator) {
this.ea = eventAggregator;
this.connection = $.hubConnection("http://localhost:8080/signalr", { useDefaultPath: false });
this.hub = this.connection.createHubProxy("myHub");
//Register a callback function to fire when a new hub message arrives
this.hub.on("sendMessage", this.processHubMessage);
//No issues so far - all this constructor code works fine
}
processHubMessage(message) {
// This doesn't work - this.ea is undefined in the scope of this function
this.ea.publish('deviceStatusUpdate', message);
}
}
The event aggregator object referenced within the callback function is not defined - I assume because it's not being called within the scope of the class. Is there a way to resolve this? How do I give the callback function access to the class properties (this.ea in my example).
Try using
this.hub.on("sendMessage", (message) => this.processHubMessage(message));
It's failing on you due to how this isn't what you're expecting it to be. By using a fat arrow function, this is what you expect it to be. This is a really frustrating part of JavaScript, but fat arrows provide a simple workaround for it.
I think you are missing the 'start' for your Proxy, also you may need to alias your view model to pass to the HubProxy.
This works for me:
constructor(eventAggregator){
this.eventAggregator = eventAggregator;
var signalrAddress = 'https://pathToYouServer';
var hubName = 'yourHubsName';
var connection = $.hubConnection(signalrAddress);
var eventHubProxy = connection.createHubProxy(hubName);
var vm = this;
eventHubProxy.on('yourBroadcastMessage', function(data) {
vm.eventAggregator.publish(data);
});
connection.start();
}