I've some issue with executing Cordova custom plugin and passing arguments to it.
I'm using function cordova.exec(callback, errCallback, pluginName, pluginAction, pluginArgs), like this:
module BlankCordovaApp2 {
"use strict";
export module Application {
export function initialize() {
document.addEventListener('deviceready', onDeviceReady, false);
}
function onDeviceReady() {
document.addEventListener('pause', onPause, false);
document.addEventListener('resume', onResume, false);
var r = Math.floor((Math.random() * 1000) + 1);
log({ id: r, value: "test" + r },
function () { alert('pass') },
function () { alert('fail') });
}
function log (log, callback, errCallback) {
cordova.exec(callback,
errCallback,
"LogstashLogger",
"LOGGER_SERVICE_ACTION_LOG",
log
);
};
function onPause() {
// TODO: This application has been suspended. Save application state here.
}
function onResume() {
// TODO: This application has been reactivated. Restore application state here.
}
}
window.onload = function () {
Application.initialize();
}
}
This way, cordova is calling my plugin's:
public boolean execute(String action, String rawArgs, CallbackContext callbackContext)
which is fine.
However, I'd like also to pass string and jsonarray to my plugin. Unfortunatelly, whatever I pass to cordova.exec, always execute for (..., String rawArgs, ...) gets called, so:
cordova.exec(..., "test") calls execute with "test" as a rawArgs but WITH double quotes! What on earth...
cordova.exec(..., [{ id: 1, value: "test1" }, { id: 1, value: "test1" }] calls execute with [{"id":891,"value":"test891"},{"id":891,"value":"test891"}] as a String...
It look like calling my function log(...) is doing some strange type casting. But I can call to cordova.exec directly only with string[] as a type, but then when I call cordova.exec(..., [ "test" ]) it should call execute with jsonarray as parameter with one string element, but it's acctualy calling execute with string parameter with value ["test"]
So question is, how to call cordova.exec properly?
Try something along these lines:
Javascript
var json1 = {foo: "bar"};
var json2 = {bar: "foo"};
cordova.exec(
successCallback,
errorCallback,
'MyPlugin',
'myAction',
[json1,json2]
);
Java
public class MyPlugin extends CordovaPlugin {
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
if ("myAction".equals(action)){
JSONObject json1 = args.getJSONObject(0);
JSONObject json2 = args.getJSONObject(1);
callbackContext.success();
}
return true;
}
}
UPDATE
Here's a working example project which illustrates how JSON can be passed from Javascript to Java on the Android platform: http://ge.tt/api/1/files/2CJwqVL2/0/blob?download
Related
Let's say I have a native method which address is expfunction.address. I tried to intercept the function call and get its arguments, general idea:
Interceptor.attach(expfunction.address, {
onEnter(args) {
console.log("\n-----\n[*] Function is called!);
for(let i in args) {
... read value of args[i] ...
}
},
onLeave(retval) {
console.log("\t\n-----\n[*] Function returns");
console.log("\t[+] Returns:", retval);
}
})
The function's arguments can be any datatype such as jboolean, jstring, jobject, etc. So how to get exactly the datatype of args[i] and properly read the value of it.
By the way, Is for(let i in args) { ... } a correct way to enumerate args array? Since trying to get args.length raises RangeError: invalid array index.
What I have tried so far (and they all return blank):
Failed 1
onEnter(args) {
for(let i in args) {
var tmp = new NativePointer(args[i]);
console.log(tmp.readPointer());
}
}
Failed 2
function getType(value) {
return Object.prototype.toString.call(value).toLowerCase();
}
...
onEnter(args) {
for(let i in args) {
var tmp = new NativePointer(args[i]);
console.log("Type:", getType(tmp));
}
}
Thank you for reading to this point :)
Im working on my first Ionic + Firebase project, and im not understanding this:
Im searching and getting an object from firebase, I can access its details on html and show it to the user.
But now I need to save the createdBy field on that object so I can use it to search for its creator on firebase.
But when I try to access that info its always undefined. Why is that? Any tips on how to fix this?
export class VisitDetailsPage implements OnInit {
public trips: Observable<HomeTripCardsModel>;
public trip: HomeTripCardsModel;
public buddyInfo;
public targetBuddyId: any;
constructor(private router: Router, private navCtrl: NavController,
public fireStorageService: FireStorageService,
private route: ActivatedRoute, public db: AngularFirestore) {
}
ngOnInit() {
const tripId: string = this.route.snapshot.paramMap.get('id');
this.db.collection('users').get()
.subscribe(querySnapshot => {
querySnapshot.forEach(doc => {
this.trips = this.fireStorageService.getTripDetail(tripId, doc.id);
this.trips.forEach((element: HomeTripCardsModel) => {
if (element?.id === tripId) {
this.trip = element;
this.targetBuddyId = element.createdBy;
}
});
});
});
// buddy
console.log(this.trip?.createdBy); // returns undefined
console.log('saved ', this.targetBuddyId) // returns undefined
}}
Data is loaded from Firebase asynchronously. If you set some breakpoints and run in the debugger, or add a log inside the subscribe method, you'll see that your console.log(this.trip?.createdBy) runs before this.trip = element has ever been run. So at that point, it indeed doesn't have a value yet.
For this reason, all code that needs data from the database, needs ot be inside the subscribe callback:
this.db.collection('users').get()
.subscribe(querySnapshot => {
querySnapshot.forEach(doc => {
this.trips = this.fireStorageService.getTripDetail(tripId, doc.id);
this.trips.forEach((element: HomeTripCardsModel) => {
if (element?.id === tripId) {
this.trip = element;
this.targetBuddyId = element.createdBy;
}
});
// buddy
console.log(this.trip?.createdBy); // returns undefined
console.log('saved ', this.targetBuddyId) // returns undefined
});
});
I’m trying to call an async Firebase function from android app and getting “INTERNAL” exception when the function returns.
Android:
private Task<String> fetchData() {
// Create the arguments to the callable function, which is just one string
Map<String, Object> data = new HashMap<>();
data.put(“id”, “abc”);
return FirebaseFunctions.getInstance()
.getHttpsCallable(“calculate”)
.call(data)
.continueWith(new Continuation<HttpsCallableResult, String>() {
#Override
public String then(#NonNull Task<HttpsCallableResult> task) throws Exception {
Map<String, Object> result = (Map<String, Object>) task.getResult().getData();
return (String)result.get(“data”);
}
});
}
Firebase Function:
exports.calculate = functions.https.onCall((data, context) => {
const text = data.id;
return calc.calculate( (err, response) => {
if(err) {
// handle error
} else {
const data = response.dataValue;
}
}).then(() => {
return {“data”: data};
});
});
Exception:
com.google.firebase.functions.FirebaseFunctionsException: INTERNAL
The documentation for handling errors in callable functions indicates that an instance of functions.https.HttpsError must be returned:
To ensure the client gets useful error details, return errors from a
callable by throwing (or returning a Promise rejected with) an
instance of functions.https.HttpsError... If an error other than
HttpsError is thrown from your functions, your client instead receives
an error with the message INTERNAL and the code internal.
It seems likely that your calc.calculate() call is returning an error that is not being handled correctly, resulting in a returned error status of INTERNAL.
Following the example in the document linked above, your code should be something like:
if(err) {
// handle error
throw new functions.https.HttpsError('calc-error', 'some error message');
} else {
const data = response.dataValue;
}
When you call httpCallable ,you will get an exception called FirebaseFunctionsExceptions. You have to handled this exceptions. Wrap your code with try and catch .
Example:-
try {
final result = await FirebaseFunctions.instance
.httpsCallable('deleteUser')
.call({});
} on FirebaseFunctionsException catch (error) {
print(error.message);
}
For more info follow this link.
I am building an Android app and I am struggling using the AsyncStorage. I want to create a function that takes a key as input and give me back the item. My problem is that when I call this function, it returns { _40: 0, _65: 0, _55: null, _72: null } instead the value I am looking for.
Here is my code :
renderList() {
async function save() {
await AsyncStorage.setItem('Title', 'hello');
}
async function fetch(key) {
const value = await AsyncStorage.getItem(key);
console.log(value) ; // Return hello
return value
}
save() ;
fetch() ;
const reponse = fetch() ;
console.log(reponse) ; // Return { _40: 0, _65: 0, _55: null, _72: null }
return (
<Text style={styles.noteElementTitle}> Aa </Text>
)
}
Edit :
I tried this :
async function getBody() {
await save();
const response = await fetch('Title');
console.log(response);
this.setstate({ title : response}) ;
}
getBody() ;
But I still get an error : TypeError: undefined is not a function (evaluating 'this.setstate({ title: response })')
What you're seeing is the Promise object returned by a function marked async. You need to either use await when calling the function, or treat the value as a promise and use then and catch. For example:
await save();
const response = await fetch();
console.log(response);
or
save()
.then(() => fetch())
.then(response => console.log(response));
Also, keep in mind that you should not be using async functions inside a render function. In your code above, you'll want to put the result of your fetch() function into component state.
Here, i am not sure why error function is not working if the C_id comming from server is incorrect. i am getting C_id from server database and passing that C_id to other server in ajax request.
$.ajax
({
url: "http://proserve.ekspeservices.com/client.php",
type: "GET",
datatype: "json",
data: {type: 'login', id: C_id},// getting C_id from server, but here if C_id is incorrect error function is not working
ContentType: "application/json",
error: function()
{
navigator.notification.alert('inCorrect Key');
},
success: function(res)
{
var simpleJson = JSON.parse(res);
myDB.transaction(function (txe1)
{
for (var i = 0; i < simpleJson.User.length; i++)
{
var Cli_id= simpleJson.User[i].id;
myDB.transaction(function (txe)
{
txe.executeSql('CREATE TABLE Client_data(Mobile integer , C_id integer, U_id integer , name text , ip integer )');
});
myDB.transaction(function (txe1)
{
var data_ins = 'INSERT INTO Client_data (Mobile,C_id,U_id) VALUES (?,?,?)';
txe1.executeSql(data_ins, [p,C_id,U_id]
,function(tx, result)
{
navigator.notification.alert('Inserted' , onSignup, 'Info', 'ok');
},
function(error)
{
navigator.notification.alert('Already Registered');
});
});
}
});
}
});
First of i must tell,you are trying to access the variable in your case its client_id whose scope is within that ftr() only.
So you need to define it globally to access it, also you need to define it as an array as you are getting multiple values at a time so you need to push in that.
Your code will be some what like this.
Also you need to call the ab() function after ftr() is finished executing as ab() output is dependent on ftr() result.So, you can go with Jquery deferred or simply call ab() within ftr() as below
var client_id = [];
function ftr()
{
myDB.transaction(function(transaction)
{
transaction.executeSql('SELECT * FROM User_data', [], function (tx, results)
{
var len = results.rows.length;
for (var i=0; i<len; i++)
{
var emp = results.rows.item(i);
client_id.push({
id: emp.C_id,
});
}
}, null);
});
ab();
}
function ab(){
console.log(client_id);
}
function onDeviceReady()
{
myDB = window.sqlitePlugin.openDatabase({name: "mydb.db", location: 'default'});
ftr();
}
Let me know if you have any queries.
Make public that variable outside of the function simple
like this
public yourVariable;
You can also try defining the variable OUTSIDE of the function, and then pass it as a parameter to the function.
This way it can be assigned a value and be used elsewhere.