http.setRequestTimeout for Android has no effect, whereas iOS works perfectly. I am using IONIC 5 with Angular. Any suggestions?
import { HTTP } from '#ionic-native/http/ngx';
...
const GetRequestTimeoutSeconcs: number = 30;
...
private http: HTTP,
...
private sendGetCommand(ip: string, command: string): any{
let _self = this;
// Send message
return new Promise(function(resolve, reject) {
_self.http.setRequestTimeout(GetRequestTimeoutSeconcs);
_self.http.get('http://' + ip + '/' + command, {}, {})
.then(data => {
resolve(_self.decodeMessage(data.data));
})
.catch(error => {
reject(error);
});
});
}
Related
I'm using the react native ble manager package to build a react native app that communicates with a python client over BLE.
When writing to a characteristic on Android (this bug does not seem to appear on IOS) the write is successful but shortly after it I receive this error:
ERROR Error writing eeee2a38-0000-1000-8000-00805f9b34fb status=14
This is the simplified code that handles connecting, notifications and writing on the Android side:
import { NativeModules, NativeEventEmitter, Platform } from 'react-native'
import BleManager, { Peripheral } from 'react-native-ble-manager'
import { END } from 'redux-saga'
import { bytesToString } from 'convert-string'
const UPDATE_SERVICE_UUID = '0000180d-aaaa-1000-8000-00805f9b34fb'
export const Characteristic =
{
WIFI_STATUS_UUID: 'bbbb2a38-0000-1000-8000-00805f9b34fb',
WIFI_CREDS_UUID: 'aaaa2a38-0000-1000-8000-00805f9b34fb',
VERSION_UUID: 'cccc2a38-0000-1000-8000-00805f9b34fb',
UPDATE_STATUS_UUID: 'dddd2a38-0000-1000-8000-00805f9b34fb',
DO_UPDATE_UUID: 'eeee2a38-0000-1000-8000-00805f9b34fb',
ERROR_UUID: 'ffff2a38-0000-1000-8000-00805f9b34fb',
}
class BLEManager {
bleManagerModule: any
bleManagerEmitter: any
scanning: boolean
dispatch: any
stopScanListener: any
peripheralDiscoverListener: any
characteristicUpdateListener: any
onDisconnectListener: any
connectTimeout: any
constructor() {
BleManager.start({ showAlert: false })
this.bleManagerModule = NativeModules.BleManager
this.bleManagerEmitter = new NativeEventEmitter(this.bleManagerModule)
this.scanning = false
}
startScan = (onPeripheralFound: (peripheral: Peripheral | null) => void) => {
if (!this.scanning) {
BleManager.scan([], 3, true)
.then(() => {
console.log('Scanning...')
this.scanning = true
this.peripheralDiscoverListener = this.bleManagerEmitter.addListener(
'BleManagerDiscoverPeripheral',
onPeripheralFound,
)
this.stopScanListener = this.bleManagerEmitter.addListener(
'BleManagerStopScan',
() => {
onPeripheralFound(END)
},
)
return
})
.catch(err => {
console.error(err)
})
} else {
console.log('already scanning')
}
return () => {
console.log('stopped scanning')
this.peripheralDiscoverListener.remove()
this.stopScanListener.remove()
}
}
getBondedDevices = (onGetBondedPeripherals: any) => {
BleManager.getBondedPeripherals().then(bondedPeripheralsArray => {
onGetBondedPeripherals(bondedPeripheralsArray)
// TODO: is the END message here necessary?
onGetBondedPeripherals(END)
return
})
return () => {}
}
connectToPeripheral = async (peripheralID: string) => {
try {
await new Promise(async (resolve, reject) => {
this.connectTimeout = setTimeout(reject, 3000)
console.log('connecting to ' + peripheralID)
try {
await BleManager.connect(peripheralID)
await BleManager.retrieveServices(peripheralID)
} catch (error) {
reject()
}
if (this.connectTimeout) {
clearTimeout(this.connectTimeout)
this.connectTimeout = null
this.onDisconnectListener = this.bleManagerEmitter.addListener(
'BleManagerDisconnectPeripheral',
this.onDisconnectPeripheral,
)
resolve()
}
})
} catch (err) {
clearTimeout(this.connectTimeout)
this.connectTimeout = null
console.error('Could not connect to device.')
throw new Error(err)
}
return
}
watchForCharacteristicsUpdates = async (
updateCharValue: (arg0: { payload: any }) => void,
peripheralID: string,
) => {
try {
await BleManager.startNotification(
peripheralID,
UPDATE_SERVICE_UUID,
Characteristic.ERROR_UUID,
)
await BleManager.startNotification(
peripheralID,
UPDATE_SERVICE_UUID,
Characteristic.VERSION_UUID,
)
await BleManager.startNotification(
peripheralID,
UPDATE_SERVICE_UUID,
Characteristic.UPDATE_STATUS_UUID,
)
} catch (e) {
updateCharValue(new Error(e))
console.error(e)
}
console.log('watch for notifications')
this.characteristicUpdateListener = this.bleManagerEmitter.addListener(
'BleManagerDidUpdateValueForCharacteristic',
({ value, characteristic }) => {
// Convert bytes array to string
const data = bytesToString(value)
console.log(
`Received ${data} (${value}) for characteristic ${characteristic}`,
)
updateCharValue({
payload: {
characteristic: characteristic,
data: data,
},
})
},
)
}
disconnectFromPeripheral = async (peripheralID: string) => {
await BleManager.disconnect(peripheralID)
this.characteristicUpdateListener.remove()
}
onDisconnectPeripheral = (peripheralID: string) => {
console.log(peripheralID + ' disconnected')
this.onDisconnectListener.remove()
}
checkIfConnected = async (peripheralID: string) => {
return await BleManager.isPeripheralConnected(peripheralID, [])
}
triggerUpdateCheck = async (peripheralID: string) => {
return await BleManager.write(
peripheralID,
UPDATE_SERVICE_UUID,
Characteristic.WIFI_STATUS_UUID,
[1],
)
}
runUpdate = async (peripheralID: string) => {
return await BleManager.write(
peripheralID,
UPDATE_SERVICE_UUID,
Characteristic.DO_UPDATE_UUID,
[1],
)
}
}
const bleManager = new BLEManager()
export default bleManager
I've researched this a bit and it seems that some people have the problem but I could not find an explanation or solution to it.
I'm even unsure where to start debugging. Any suggestions are welcome.
Details:
Device: [Pixel 6]
OS: [Android 12]
react-native-ble-manager version: ^8.4.1
react-native version: 0.67.4
Note: I've also asked this question on Github: https://github.com/innoveit/react-native-ble-manager/issues/887
The problem (as mentioned by Martijn) was the bug in Bluez which is fixed in 5.65. Simply upgrading and clearing the Bluetooth cache fixed it.
I run a React Native app on Android emulator but found networking does not work, I run it on iOS it works fine.
Here is the simple code:
import React from 'react';
import {StyleSheet, View, Text} from 'react-native';
export default () => {
React.useEffect(() => {
const useFetch = async () => {
try {
console.log('fetch ...');
let response = await fetch('https://mytestdomain.com');
console.log(response.status);
// let json = await response.json();
} catch (error) {
console.log(error);
}
};
useFetch();
const useXMLHttpRequest = async () => {
try {
var request = new XMLHttpRequest();
request.onreadystatechange = (e) => {
if (request.readyState !== 4) {
console.log(request.readyState);
return;
}
if (request.status === 200) {
console.log('success', request.responseText);
} else {
console.warn('error');
}
};
request.open('GET', 'https://mytestdomain.com');
request.send();
} catch (error) {
console.log(error);
}
};
useXMLHttpRequest();
}, []);
return (
<View style={styles.layout}>
<Text>React Native Android networking</Text>
</View>
);
};
const styles = StyleSheet.create({
layout: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
By call useFetch() I just see 'fetch ...' in console, even can not see response.status, and there is no error from catch.
By call useXMLHttpRequest() I see request.readyState is 1.
Thanks advance for any help
You probably should give this asynchronous log a more explicit message to find this specific one among other logs, like :
console.log("RS : " + response.status);
I tried to reproduce your issue, and I can't, it works on my Android simulator just fine.
Would you please share your console logs ?
A workaround is to use the #react-native-community/netinfo library to determine whether you have internet access or not.
Beware, it could be slow.
This library provides a listener with the connection details changes. Getting the connection details can be slow... you would have to test it on real devices to determine whether this workaround is efficient or not.
Quick Demo based on your source code :
[...]
import { StyleSheet, View, Text } from "react-native";
+import NetInfo from "#react-native-community/netinfo";
export default () => {
- React.useEffect(() => {
+ NetInfo.addEventListener((netInfo) => {
const useFetch = async () => {
try {
- console.log("fetch ...");
- let response = await fetch("https://mytestdomain.com");
- console.log(response.status);
- // let json = await response.json();
+ // Just because there is a connection, it does not mean that internet is accessible, so test both isConnected and isInternetReachable
+ if (netInfo.isConnected && netInfo.isInternetReachable) {
+ console.log("fetch ...");
+ let response = await fetch(
+ "https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch"
+ );
+ console.log("start 1");
+ console.log("success 1", response.status);
+ console.log("stop 1");
+ } else {
+ console.log("internet is not ready");
+ }
} catch (error) {
[...]
I am trying to display Google Maps in my Ionic app & center on my current location.
When I run this on my laptop, it displays as expected.
But when I try to run it on my mobile device, the map isn't rendering.
Here is the code:
ngAfterViewInit() {
this.locateUser();
console.log('My Coords', this.coordinates);
this.getGoogleMaps().then(googleMaps => {
const mapEl = this.mapElementRef.nativeElement;
const map = new googleMaps.Map(mapEl, {
center: this.coordinates,
zoom: 16
});
googleMaps.event.addListenerOnce(map, 'idle', () => {
this.renderer.addClass(mapEl, 'visible');
});
}).catch(err => {
console.log('Google Maps error:', err);
});
}
private getGoogleMaps() {
const win = window as any;
const googleModule = win.google;
if (googleModule && googleModule.maps) {
return Promise.resolve(googleModule.maps);
}
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = 'https://maps.googleapis.com/maps/api/js?key=myAPIKey';
script.async = true;
script.defer = true;
document.body.appendChild(script);
script.onload = () => {
const loadedGoogleModule = win.google;
if (loadedGoogleModule && loadedGoogleModule.maps) {
resolve(loadedGoogleModule.maps);
} else {
reject('Google Maps SDK not available.');
}
};
});
}
private locateUser() {
if (!Capacitor.isPluginAvailable('Geolocation')) {
this.showErrorAlert();
return;
}
Plugins.Geolocation.getCurrentPosition()
.then(geoPosition => {
this.coordinates = {
lat: geoPosition.coords.latitude,
lng: geoPosition.coords.longitude
};
console.log(this.coordinates);
})
.catch(err => {
this.showErrorAlert();
});
}
Can someone please tell me why this is working on my laptop, but not on my mobile?
Also, here are the steps I'm taking to run on the mobile:
ionic build
ionic capacitor run android
Then I run the app in Android Studio.
I have a react-native app on Android and a backend server written in NodeJS + Express and I'm using multer to handle file uploads.
const multer = require('multer');
const mime = require('mime');
const crypto = require('crypto');
const storage = multer.diskStorage({
destination: (req, file, cb) => cb(null, config.uploads),
filename: (req, file, cb) => {
crypto.pseudoRandomBytes(16, (err, raw) => {
cb(null, raw.toString('hex') + Date.now() + '.' + mime.extension(file.mimetype));
});
}
});
const upload = multer({ storage });
const Router = require('express').Router;
const controller = require('./upload.controller');
const router = new Router();
const auth = require('./../../auth/auth.service');
router.post('/', [auth.isAuthenticated(), upload.any()], controller.create);
module.exports = router;
And on my react-native app I try to do like this:
ImagePicker.launchCamera(options, image => {
let { uri } = image
const API_URL = 'http://192.168.1.2:9000/api/uploads'
var form = new FormData();
form.append("FormData", true)
form.append("access_token", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjU3YjgyZGQ2MTEwZDcwYmEwYjUxZjM5YyIsImlzTWVkaWMiOnRydWUsImlhdCI6MTQ3MTY4ODE1MiwiZXhwIjoxNDcxNzA2MTUyfQ.gPeql5g66Am4Txl1WqnbvOWJaD8srTK_6vihOJ6kFbY")
form.append("Content-Type", "image/jpg")
form.append('image', uri)
fetch(API_URL, {body: form, mode: "FormData", method: "post", headers: {"Content-Type": "multipart/form-data"}})
.then((response) => console.log(response))
.catch((error) => {
console.log("ERROR " + error)
})
.then((responseData) => {
console.log("Succes "+ responseData)
})
.done();
})
But when I try to upload I recive the following error
multipart body must have at least one part
I am doing something wrong?
Does anybody knows a better solution to do this?
Fetch may not support Blob and FormData at this moment, but you can use XMLHttpRequest polyfill instead.
let xhr = new XMLHttpRequest()
xhr.open('post', `http://myserver.com/upload-form`)
xhr.send(form)
xhr.onerror = function(e) {
console.log('err', e)
}
xhr.onreadystatechange = function() {
if(this.readyState === this.DONE) {
console.log(this.response)
}
}
This question already has an answer here:
Variable not updating with fetch response data in Angular 2 beta
(1 answer)
Closed 6 years ago.
I try to explain in English, but I don't speak it.
I'm working in a Ionic 2. I try to do a http request with post method and I am emulate in SDK Android emulator and I can see in the logcat:
Cannot call method 'post' of undefined at
file:///android_asset/www/build/js/app.bundle.js:2265
But I review and don't see anything, I rewrite my clientId and ClientSecret to can post here. I put a trace console.log(this.http) in the login function and this attribute is undefined, althought is inject in the class' constructor.
My code:
import {Page, Platform} from 'ionic-angular';
import {Http, Headers, HTTP_PROVIDERS} from 'angular2/http';
#Page({
templateUrl: 'build/pages/home/home.html',
providers: [ HTTP_PROVIDERS ]
})
export class HomePage {
static get parameters() {
return [[Platform],[Http]];
}
constructor(platform, http) {
this.platform = platform;
this.http = http;
this.clientId = "clientId";
this.clientSecret = "clientSecret";
}
login() {
this.platform.ready().then(() => {
this.googleLogin().then((success) => {
alert(success.access_token);
}, (error) => {
alert(error);
});
});
}
googleLogin() {
return new Promise(function(resolve, reject) {
var browserRef = window.cordova.InAppBrowser.open("https://accounts.google.com/o/oauth2/auth?client_id=" + "clientId" + "&redirect_uri=http://localhost/callback&scope=email%20profile&approval_prompt=force&response_type=code&access_type=offline", "_blank", "location=no,clearsessioncache=yes,clearcache=yes");
browserRef.addEventListener("loadstart", (event) => {
if ((event.url).indexOf("http://localhost/callback") === 0) {
var headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
var parameters = "client_id=" + "clientId" + "&client_secret=" + "clientSecret" + "&redirect_uri=http://localhost/callback" + "&grant_type=authorization_code" + "&code=" + requestToken
var requestToken = (event.url).split("code=")[1];
this.http.post("https://accounts.google.com/o/oauth2/token", parameters, { header:headers })
.subscribe( data => { resolve(data); },
error => { reject("Problem authenticating with Google"); }
);
browserRef.removeEventListener("exit", (event) => {});
browserRef.close();
}
});
browserRef.addEventListener("exit", function(event) {
reject("The Google sign in flow was canceled");
});
});
}
}
The code tries to authenticate with Google OAuth2, althought the error seems to be in the attributes in the constructor(http, clientId, clientSecret) there are not defined when the login function is called. I don't know what's wrong!
It might have something to do with the scoping of 'this', depending on what calls the googleLogin function.
Try using an arrow function:
googleLogin = () => {
...
}
It's because you don't use an arrow function when defining your promise. So the this keyword doesn't correspond to the instance of the component itself. With arrow functions, you can use the lexical this that will correspond to the component instance.
googleLogin() {
return new Promise((resolve, reject) => {
(...)
});
}
instead of
googleLogin() {
return new Promise(function(resolve, reject) {
(...)
});
}
See this link for more hints about the lexical this of arrow functions:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions.