Skip to content

iOS - Camera not opening after giving permissions #210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jorwoody opened this issue Jul 3, 2019 · 5 comments
Closed

iOS - Camera not opening after giving permissions #210

jorwoody opened this issue Jul 3, 2019 · 5 comments

Comments

@jorwoody
Copy link

jorwoody commented Jul 3, 2019

Which platform(s) does your issue occur on?

  • iOS
  • device.
    -- Tested on Browserstack app-live (real device cloud) with iPhone XS/8/6.
    -- Seems to affect all iOS versions.

Please, provide the following version numbers that your issue occurs with:

  • CLI: (run tns --version to fetch it)
    5.3.1

  • Cross-platform modules:
    5.4.3

  • Runtime(s):
    "tns-android": {
    "version": "5.4.0"
    },
    "tns-ios": {
    "version": "5.4.0"
    }

  • Plugin(s):
    "dependencies": {
    "@angular/animations": "8.0.0",
    "@angular/common": "8.0.0",
    "@angular/compiler": "8.0.0",
    "@angular/core": "8.0.0",
    "@angular/forms": "8.0.0",
    "@angular/http": "8.0.0-beta.10",
    "@angular/platform-browser": "8.0.0",
    "@angular/platform-browser-dynamic": "8.0.0",
    "@angular/router": "8.0.0",
    "@jorwoody/nativescript-contacts": "^1.1.0",
    "dayjs": "^1.8.14",
    "js-base64": "^2.5.1",
    "nativescript-angular": "^8.0.1",
    "nativescript-camera": "^4.5.0",
    "nativescript-cardview": "^3.2.0",
    "nativescript-checkbox": "^3.0.3",
    "nativescript-directions": "^1.3.0",
    "nativescript-imagepicker": "^6.2.0",
    "nativescript-drop-down": "^5.0.1",
    "nativescript-email": "^1.5.4",
    "nativescript-handle-file": "^4.0.0",
    "nativescript-iqkeyboardmanager": "^1.5.1",
    "nativescript-localstorage": "^2.0.0",
    "nativescript-masked-text-field": "^4.0.2",
    "nativescript-orientation": "^2.2.1",
    "nativescript-permissions": "^1.3.6",
    "nativescript-phone": "^1.4.0",
    "nativescript-platform-css": "^1.6.9",
    "nativescript-popup": "^1.5.0",
    "nativescript-theme-core": "^1.0.6",
    "nativescript-ui-sidedrawer": "^6.0.0",
    "reflect-metadata": "~0.1.10",
    "rxjs": "^6.3.3",
    "tns-core-modules": "^5.4.3",
    "zone.js": "^0.8.4"
    },
    "devDependencies": {
    "@angular/cli": "^8.0.1",
    "@angular/compiler-cli": "8.0.0",
    "@nativescript/schematics": "^0.6.0",
    "@ngtools/webpack": "8.0.0",
    "@types/chai": "^4.1.7",
    "@types/js-base64": "^2.3.1",
    "@types/mocha": "^5.2.7",
    "@types/node": "^12.0.10",
    "ajv": "^6.10.0",
    "axios": "^0.19.0",
    "browserstack-local": "^1.4.0",
    "chai": "^4.2.0",
    "codelyzer": "^5.1.0",
    "date-fns": "^1.30.1",
    "dotenv": "^8.0.0",
    "fs-extra": "^8.0.1",
    "husky": "^2.6.0",
    "listr": "^0.14.3",
    "mocha": "^6.1.4",
    "mochawesome": "^4.0.1",
    "nanoid": "^2.0.3",
    "nanoid-dictionary": "^2.0.0",
    "nativescript-dev-appium": "^5.3.0",
    "nativescript-dev-sass": "^1.7.0",
    "nativescript-dev-typescript": "^0.10.0",
    "nativescript-dev-webpack": "^0.24.1",
    "npm-check": "^5.9.0",
    "open": "^6.3.0",
    "precise-commits": "^1.0.2",
    "prettier": "^1.18.2",
    "semver": "^6.1.2",
    "strip-ansi-stream": "^1.0.0",
    "tns-platform-declarations": "^5.4.3",
    "tslint": "^5.18.0",
    "tslint-config-prettier": "^1.18.0",
    "typescript": "~3.4.5",
    "xcode": "^2.0.0",
    "yargs": "^13.2.4"
    }

Please, tell us how to recreate the issue in as much detail as possible.

I've created a service which calls the nativescript-camera plugin in order to get an ImageAsset which will be used for uploading to my service. Trying to call the plugin to take a picture on an iOS device (tested through app-live device cloud on BrowserStack) does not open Camera, and returns failure.

NOTES:

  • Taking picture on Android emulator works fine.
  • Taking picture on Android device (Galaxy S9) works after ensuring camera app has been opened once before (support for issue Camera does not offer tick nor cross to accept photo after accepting permissions and taking photo #161)
  • Taking picture on iOS emulator does not work because iOS emulator provides no camera access
  • My info.plist file contains entries for NSCameraUsageDescription and NSPhotoLibraryUsageDescription
  • Permissions are requested when "takePhoto()" is called, but it seems that the camera activity does not start after permissions are granted

Is there any code involved?

Here is the relevant service code.

import { Injectable } from '@angular/core'
import * as NativeCamera from 'nativescript-camera'
import * as FileSystem from 'tns-core-modules/file-system'
import { ImageAsset } from 'tns-core-modules/image-asset/image-asset'
import { ImageSource } from 'tns-core-modules/image-source/image-source'
import { isAndroid } from 'tns-core-modules/ui/page/page'

import { ClaimAttachmentModel } from '~/app/core/models/uploaded-file.model'

@Injectable({
	providedIn: 'root',
})
export class NativePhotoService {
	constructor() {}

	// See https://market.nativescript.org/plugins/nativescript-camera for more info on plugin usage
	async takePhoto(fileName: string): Promise<ClaimAttachmentModel> {
		if (!NativeCamera.isAvailable) {
			throw new Error('Camera is not available.') // iOS simulator will always return false, as there is no camera hardware
		}
		const permissionGranted = await NativeCamera.requestPermissions()

		if (permissionGranted) {
			const asset: ImageAsset = await NativeCamera.takePicture()
			return this.buildClaimAttachment(asset, fileName)
		}
	}

    private async buildClaimAttachment(
		asset: ImageAsset,
		fileName?: string,
	): Promise<ClaimAttachmentModel> {
		let path: string
		let imageSource = new ImageSource()
		try {
			imageSource = await imageSource.fromAsset(asset)
		} catch (e) {
			// imageSource cannot be instantiated from "broken" file
			throw Error('Asset was corrupt or invalid; imageSource could not be instantiated.')
		}

		if (isAndroid) {
			// on taking photo, asset.android is temp location which we can reference
			// on selecting photo, asset.android is the path to the file
			path = asset.android
		} else {
			// iOS returns PHAsset, so we need to save to file system to get a path for reference
			if (!fileName) {
				// on selecting photo, retrieve URI to determine fileName
				const uriRequestOptions = PHImageRequestOptions.alloc().init()
				uriRequestOptions.synchronous = true

				PHImageManager.defaultManager().requestImageDataForAssetOptionsResultHandler(
					asset.ios,
					uriRequestOptions,
					(data, util, orientation, info) => {
						const uri: string = info.objectForKey('PHImageFileURLKey').toString()
						fileName = this.getFileNameFromPath(uri)
					},
				)
			}

			const folder = FileSystem.knownFolders.temp()
			path = FileSystem.path.join(folder.path, fileName)
			const saved = imageSource.saveToFile(path, 'jpg')
			if (!saved) {
				throw Error('Failed to save image to device.')
			}
		}

		if (!fileName) {
			fileName = this.getFileNameFromPath(path)
		}

		const claimAttachment = {
			fileName,
			path,
			imageSource,
		}
		return claimAttachment
	}
}
@VladimirAmiorkov
Copy link
Contributor

Hi,

I was not able to reproduce this issue in our demo-angular application. In our test app when you correctly chain the requestPermissions() Promise and its .then call the takePicture() it is correctly executed after like it is shown here.

Can you provide us with a runnable project that shows the issue you are reporting when creating a custom service that wraps those APIs, you can use our playground to create a project.

@jorwoody
Copy link
Author

jorwoody commented Jul 9, 2019

Thanks for the response @VladimirAmiorkov . I had implemented this plugin using TypeScript's async/await functionality... but it seems that for some reason this strategy does not work for iOS permissions request.

Before I attempted to create a runnable example project, I tried following the pattern used in the demo application (chaining promises/callbacks) and it worked. Strange, but it works that way so I'm going with it. Would be nice to get async/await functionality working for cleaner code, but c'est la vie!

@VladimirAmiorkov
Copy link
Contributor

Indeed it is not usual to that this is not working for iOS only. If you can send me a runnable project I would be happy to review it and see if there is something that could be done to help out in this scenario.

@jorwoody
Copy link
Author

jorwoody commented Jul 9, 2019

@VladimirAmiorkov I have started working on an example project, so I will try and finish that when I have time in the coming weeks.

@elena-p
Copy link
Contributor

elena-p commented Sep 17, 2019

closing due to inactivity

@elena-p elena-p closed this as completed Sep 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants