Ionic 3 Ios plugins not working until app gets in background - ios

I'm building a cross platform app using Ionic 3.19.1,
On Android everything runs fine, but when i build the app for IOS and then run it on a device using Xcode i get some unexpected behaviour:
Expected:
1) Clicking on a button, the dialer should open and make a call
2) Clicking on a button, the camera should open
Actual:
None of those actions happen until the app gets into background, for example when opening the notifications bar or the tools bar on the bottom.
CODE:
This is the code used for making a phone call, using #ionic-native/call-number
this.callNumber.callNumber("+123456789", true)
.then(() => this.navCtrl.setRoot(CompletedPage))
.catch((error) => console.log(error));
This is the code used to open the camera, using #ionic-native/camera
const options: CameraOptions = {
quality: 60,
targetHeight: 600,
targetWidth: 600,
destinationType: this.camera.DestinationType.DATA_URL,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE
}
this.camera.getPicture(options).then((imageData) => {
}
The code and cordova plugins are correctly set up and working fine, the only problem is that they don't get executed until some event occurs on the page (i guess focus event or something related),
i'm not getting errors for the call-number, but i'm getting a warning for the camera:
Attempt to present <CDVCameraPicker: 0x17a84e00> on <MainViewController: 0x176345a0> whose view is not in the window hierarchy!
I looked around for that message but i couldn't fine nothing related to ionic.
Any kind of help or just link to resources will be appreciated!

Related

How can iOS 3D touch on app be automated?

I write Appium UI tests for my iOS app. Some of the tests have such workflow:
an app is sent to background
the user does "force touch" on the app's icon, until menu (shortcuts) appear
an app is launched from this shortcut
My environment:
Simulator iOS 13.2
appium 1.15.0
Appium Python Client 0.47
I've tried such code (Python), it doesn't do "force touch":
self.driver.background_app(-1) # this works: sends an app to backround
args = {'duration': 5, 'x': 200, 'y': 200}
self.driver.execute_script("mobile:touchAndHold", args) # this doesn't work: force touch on Home screen
(I've tried to adjust coords, e.g. (150,200), (260,400) - no app icon was pressed).
I've tried AppleScript, but all I can do now is to activate Simulator app. :)
What I've found but it's not working:
https://saucelabs.com/blog/how-to-automate-3d-force-touch-with-appium: in this post "press" command was used with "element" = AppName, but my selenium driver says "press" requires "x", "y", not "element"
https://developers.perfectomobile.com/display/TT/Using+iOS+3D+Touch: in this post, driver.executeScript("mobile:touch:tap", parms) is used, but my driver says there's no command "mobile:touch:tap":
selenium.common.exceptions.WebDriverException: Message: Unknown mobile command 'touch:tap'. Only scroll, swipe, pinch, doubleTap, twoFingerTap, touchAndHold, tap, dragFromToForDuration, selectPickerWheelValue, alert, setPasteboard, getPasteboard, source, getContexts, installApp, isAppInstalled, removeApp, launchApp, terminateApp, queryAppState, activateApp, viewportScreenshot, startPerfRecord, stopPerfRecord, installCertificate, startLogsBroadcast, stopLogsBroadcast, batteryInfo, deviceInfo, activeAppInfo, pressButton, enrollBiometric, sendBiometricMatch, isBiometricEnrolled, clearKeychains, getPermission, siriCommand commands are supported.
I've looked at XCUITestDriver documentation/code, e.g. https://github.com/appium/appium-xcuitest-driver/blob/master/lib/commands/execute.js, and can't see any 3D-touch related stuff.
So do you know:
1. how to automate 3D-touch on app icon in iOS Simulator?
2. How to check if it's supported by XCUITest-Driver?
3. Can it be automated by smth like AppleScript?
Thanks in advance :)
If you mean like https://i.stack.imgur.com/3Fo7v.png, you can open it like below.
(Ruby code)
# Long press 'Contacts' icon with W3C actions
el = #driver.find_element :name, 'Contacts'
action_builder = #driver.action
action_builder.move_to(el)
.pointer_down(:left)
.pause(action_builder.pointer_inputs[0], 2)
.pointer_up(:left).perform
https://appium.io/docs/en/commands/interactions/actions/ is the API.
You can find Python, too.
(iOS 13 does not provide '3D touch'. The feature has been long-press style)

Is it possible to access camera from inappbrowser/webview on iOS

I have tried every possible way to access camera on webview on cordova.
It work on android, but doesn't work on iOS.
Can someone explain how to implement access camera feature via cordova webview on iOS thanks.
Inappbrowser side (Angular)
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices
.getUserMedia({ video: { facingMode: 'environment' } })
.then(stream => {
// this.videoDom.srcObject = stream;
this.videoDom.srcObject = stream;
this.videoDom.setAttribute('playsinline', 'true');
this.videoDom.play();
this.stream = stream.getTracks();
requestAnimationFrame(tick);
})
}
Cordova side
I have install cordova-plugin-camera and add permission in config.xml on ios platform.
On iOS11/12 navigator.getMediaDevices is not available for WKWebView and UIWebView. It is only available for Safari. (https://forums.developer.apple.com/thread/88052)
WebRTC is only supported in Safari. No WKWebView, not even
SFSafariViewController.
You can try to use this plugin normally should solve your problem: https://github.com/phonegap/phonegap-plugin-media-stream
navigator.mediaDevices.getUserMedia({
'audio': true,
'video': {
facingMode: 'environment'
}
}).then(function(mediaStream) {
// Do what you want with
}
There is a simpler way, just use input type file
This shows the camera for taking a picture
<input type="file" accept="image/*" capture>
This for recording video
<input type="file" accept="video/*" capture>
This will prompt to take a picture or video, choose from the photo library or explore files
<input type="file">
There are a few other combinations. But it probably doesn't work on Android
This is a duplicate of: NotReadableError: Could not start source (Please read this link as its related to Cordova and getUserMedia) and potentially Progressive Web App: Error Accessing navigator.mediaDevices.getUserMedia?
There are changes to Safari on iOS 13 & Safari 13: https://developer.apple.com/documentation/safari_release_notes/safari_13_release_notes
SFSafariViewController has gained getUserMedia functionality (!!!)
https://bugs.webkit.org/show_bug.cgi?id=183201
However WKWebView does not seem to gain getUserMedia functionality (this might be a bug, watch the webkit link closely):
https://bugs.chromium.org/p/chromium/issues/detail?id=752458
https://bugs.webkit.org/show_bug.cgi?id=185448
iOS 13 and Safari 13 release notes:
https://developer.apple.com/documentation/ios_ipados_release_notes/ios_13_release_notes
https://developer.apple.com/documentation/safari_release_notes/safari_13_release_notes
I've thought of a hacky way you can make this work on iOS by using the new postMessage API feature of cordova-plugin-inappbrowser which enables you to send messages from pages loaded into the Inappbrowser Webview back to the main Cordova app Webview.
This is not present in the latest release on npm (3.0.0), so you'd need to install the master version (3.1.0-dev) directly from Github:
cordova plugin add https://github.com/apache/cordova-plugin-inappbrowser
In the page loaded into the inappbrowser, you can then post messages back to the Cordova app webview:
function openCamera(){
postMessage({
action: "camera"
});
}
function postMessage(message){
if(!webkit.messageHandlers.cordova_iab) throw "Cordova IAB postMessage API not found!";
webkit.messageHandlers.cordova_iab.postMessage(JSON.stringify(message));
}
<button onclick="openCamera()">Open camera<button>
On the Cordova app side, you can then listen for that message and respond to it:
var iab = cordova.InAppBrowser.open(myUrl, '_blank', iabOpts);
iab.addEventListener('message', function (e) {
if(e.data.action === 'camera'){
openCamera();
}
});
function openCamera() {
var animationDelay = 500; // delay to wait for camera window animation
navigator.camera.getPicture(function(){
log("successfully opened camera");
if (device.platform === "iOS"){
// unhide IAB
iab.show();
}
}, function(cameraError){
error("error opening camera: "+cameraError);
if (device.platform === "iOS"){
iab.show();
}
});
if (device.platform === "iOS"){
// hide IAB so camera window is in view
setTimeout(iab.hide, animationDelay);
}
}
This allows you to directly call cordova-plugin-camera from within the inappbrowser.
However it is hacky because on iOS, by default the camera window will appear below the inappbrowser window in the view hierarchy and hence not be visible.
My hack is to hide the inappbrowser window upon opening the camera, which causes the camera window to be at the top of the visible view hierarcy and be displayed.
However, upon dismissing the camera window, the Cordova app window will briefly be displayed while the inappbrowser window is being animated to show again.
I created a test case example in my inappbrowser test app repo: https://github.com/dpa99c/cordova-plugin-inappbrowser-test/tree/camera
You can try it like this:
git clone -b camera https://github.com/dpa99c/cordova-plugin-inappbrowser-test
cd cordova-plugin-inappbrowser-test
cordova platform add ios
cordova run ios

how to take screenshot of IOS phone using react-native

Is it possible to programmatically take a screenshot of the current phone view while the react-native app is in the background? The expo api for takeSnapshotAsync requires a view ref to work. I do not want to capture the actual app itself. I want to capture whatever the user is doing on their phone.
I believe this one should be able to do what you want: https://github.com/gre/react-native-view-shot
import RNViewShot from "react-native-view-shot";
RNViewShot.takeSnapshot(viewRef, {
format: "jpeg",
quality: 0.8
})
.then(
uri => console.log("Image saved to", uri),
error => console.error("Oops, snapshot failed", error)
);
Try to call RNViewShot in setInterval maybe it will work even when the app is minimalized. If RNViewShot will not work then you will have to create your own native ios module.

Ionic 2 Camera select Video on iOS not working

I'm developing a App with Ionic 2 and I'm have problems with #ionic-native/Camera. I've this code on Upload.ts
let loader = this.loading.create({
content: 'Carregando video....'
});
loader.present().then(() => {
const options: CameraOptions = {
quality: 100,
destinationType: this.camera.DestinationType.FILE_URI,
sourceType: this.camera.PictureSourceType.PHOTOLIBRARY,
mediaType: this.camera.MediaType.VIDEO,
}
this.camera.getPicture(options).then((videoData) => {
this.uploadForm.controls['file'].setValue(videoData)
loader.dismiss();
}, (err) => {
console.log(err);
});
});
This code works fine in Android, but when I run ionic cordova run ios -lc, the promise this.camera.getPicture(options) is never resolved, so the loader keep running forever.
Thanks in advance!
So, I found the problem. First thing is that native components bugs with -l (--livereload). I don't know how to explain why but I got this information from the Ionic Worldwide slack. A member from Ionic Team said:
"live-reload on a device can cause issues with plugins and file system".
So I used this video to understand how to debbug the APP using the iOS emulator and Safari.
https://www.youtube.com/watch?v=Aob749bkoLY
A little brief of the video: when using iOS emulator, you can access the menu Developer > Emulator > <App Name>. A new window with inspector tools will open and logs from the emulator will appear on this window.
I found out that's the video url was incorrect. Before, to be compatible with Android, I've this code responsible to find the video pointer in system and send to the server:
filePath = 'file:///' + this.uploadForm.controls['file'].value;
But, iOS File Picker already has a "file:///" prefix. So prefixing it again made it wrong. So I updated the code to be like this:
if (this.platform.is('android')) {
filePath = 'file:///' + this.uploadForm.controls['file'].value;
} else {
filePath = this.uploadForm.controls['file'].value;
}
This resolved the problem.

Turning camera off in fine-uploader on iOS

I'm very new to fine-uploader; I hope my question is relevant...
I'm trying to disable the camera for users of our Web App on iPad and iPhone only (iOS), both for Safari and Chrome. I have tried setting the option camera: {ios: false} but the camera option still shows in Safari and Chrome. When I use workarounds: { ios8BrowserCrash: true}, the camera option does disappear in Chrome but still shows in Safari. What am I missing?
We are using fine-uploader 5.1.2, I briefly tried 5.2.2 with the same results. The app is HTML5, Javascript, Angular with Java back-end. I have tested on iPad with iOS 8.3, 8.4 and 9 beta.
As an aside, the reason I'm trying to disable the camera is due to iOS often crashing when loading the image from the camera. I have found the application crashing a lot less when loading from the device image library, bypassing the camera. Is that a known issue with iPad/iPhones?
Thanks in advance for the help.
Thanks #Ray. For reference, I'm now using the latest FineUploader version 5.3.0.
As you suggested the multiple attribute was being removed. I traced it to the input.removeAttribute("multiple"); code below (s3.fine-uploader.js):
setMultiple: function(isMultiple, optInput) {
var input = optInput || this.getInput();
// Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash
// before the file chooser appears if the file input doesn't contain a multiple attribute.
// See #1283.
if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {
input.setAttribute("multiple", "");
}
else {
if (isMultiple) {
input.setAttribute("multiple", "");
}
else {
input.removeAttribute("multiple");
}
}
},
Despite options.ios8BrowserCrashWorkaround being set to true in my code (ios8BrowserCrash: true), the program was still going through to removeAttribute("multiple") line of code when running on IPad/Safari.
After several tries and errors I found out that (possibly...) the library code was missing testing for the condition qq.iosSafari()on an iPad (iOS 8.3) ; the qq.iosSafariWebView() test isn't sufficient to detect the Safari browser on my iPad, therefore missing the code where the multiple attribute is set.
I found out that the following options values in my calling code fixed the issue.
function initialiseS3() {
uploader = new qq.s3.FineUploader({
element: $element[0],
template: $(contents)[0],
debug: false,
// iosEmptyVideos workaround must be false to enable FineUploader to keep multiple:true in iOS
workarounds: {
iosEmptyVideos: false,
ios8BrowserCrash: true
},
// Must add the test qq.iosSafari() to set multiple to true and have the camera turned off on iPad
multiple: qq.ios8() && (qq.iosSafari() || qq.iosChrome() || qq.iosSafariWebView()) ? true : false,
camera: {
ios: false
},
… (more initialisations)
`
The last catch was to override the default value for the workaround option iosEmptyVideos and set it to iosEmptyVideos: false to avoid the library forcing multiple to false again. I hope this makes sense…

Resources