I'm using a card scan library that has a boolean method call to check if the camera permissions have been set. Is there a way in Swift 3 that I can manually set the permissions based on an alert action controller.
I don't want to to create another imagepicker if one is already been created via the library.
Can this be done?
Thanks
No you can not do that. But of course you can let user to grant permission with following code and then you can store the value in a bool variable for future use.
if AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo) == AVAuthorizationStatus.authorized
{
// Already Authorized
}
else
{
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: { (granted :Bool) -> Void in
if granted == true
{
// User Granted
}
else
{
// User Rejected
}
});
}
No.
For security reasons, there is no way to set the app permissions programmatically, as this can easily cause manipulative behaviours in potentially malicious apps. Apple also wants to develop a streamlined interface for crucial security settings, including permissions for individual apps.
Related
As per the quick read the purpose of this key
"PHPhotoLibraryPreventAutomaticLimitedAccessAlert" is to prevent limited library access. I have added this option in info.plist but it still shows "Select photos" option in permissions dialogue.
The code of getting permissions is following.
func checkPhotoLibraryPermission(completionBlock completion: #escaping ()->Void) {
let status = PHPhotoLibrary.authorizationStatus()
switch status {
case .authorized:
completion()
break
case .notDetermined,.denied,.restricted:
// ask for permissions
PHPhotoLibrary.requestAuthorization { (status) in
switch status {
case .authorized:
completion()
break
case .notDetermined,.denied,.restricted:
self.alertToEncouragePhotoLibraryAccessWhenApplicationStarts()
break
case .limited:
break
}
}
break
case .limited:
break
}
}
Anyone please mention what is the exact purpose of this key and is it possible to even force drop this option ?
As far as i know the purpose of this key "PHPhotoLibraryPreventAutomaticLimitedAccessAlert" is to prevent limited library access.
Then you "know" wrong. You cannot prevent use of limited authorization. It is built into the system and the user can always specify it.
So what is this key for? Well, if the user does specify limited access, the system may put up the Select Photos interface again from time to time to see whether the user wants to change what photos your app can access. PHPhotoLibraryPreventAutomaticLimitedAccessAlert prevents that. It does not prevent the user from specifying limited access in the initial authorization request alert or the Settings app.
I am making a music app with swift. The app lets users play music through their Apple Music subscription via their Apple Music app. I am able to check whether the user has an Apple Music subscription via:
SKCloudServiceController().requestCapabilities { (capability:SKCloudServiceCapability, err:Error?) in
guard err == nil else {
print("error in capability check is \(err!)")
return
}
if capability.contains(SKCloudServiceCapability.musicCatalogPlayback) {
print("user has Apple Music subscription")
}
if capability.contains(SKCloudServiceCapability.musicCatalogSubscriptionEligible) {
print("user does not have subscription")
}
}
However: there are scenarios where somebody will, for some reason, have an Apple Music subscription but not have the Apple Music app downloaded on their device. If the user has the subscription but not the device, I want to essentially treat that case as if they do not have a subscription at all, i.e. we cannot play music via Apple Music.
So, I go searching for ways to add a check for if Apple Music is on the user's device. I find this answer: Check whether an app is installed using Swift combined with this resource for finding Apple Music's url scheme and conclude I can check if a user has both an Apple Music subscription and the Apple Music app installed on their device via:
SKCloudServiceController()requestCapabilities { (capability:SKCloudServiceCapability, err:Error?) in
guard err == nil else {
print("error in capability check is \(err!)")
return
}
if capability.contains(SKCloudServiceCapability.musicCatalogPlayback) && UIApplication.shared.canOpenURL(URL(string: "music://")!) {
print("user has Apple Music subscription and has the apple music app installed")
}
if capability.contains(SKCloudServiceCapability.musicCatalogSubscriptionEligible) || !UIApplication.shared.canOpenURL(URL(string: "music://")!) {
print("user does not have subscription or doesn't have apple music installed")
}
}
The issue is, even after deleting Apple Music from my device, the first case, i.e. the one that prints user has Apple Music subscription and has the apple music app installed is still being called. I believe I have the correct url scheme because when changing "music://" to "musi://", the second case, i.e. the one that prints user does not have subscription or doesn't have apple music installed is being called.
When trying to open URL(string: "music://") with Apple Music deleted via UIApplication.shared.open(URL(string: "music://")!), I am hit with the following alert:
So why is the device saying that I can open URL(string: "music://") even after Apple Music is deleted? Is the URL capable of being opened, but the result is simply the presentation of the above alert? Is this the correct way to confirm that the user has Apple Music installed on their device? Is there even a way to confirm the user has Apple Music installed on their device? If Apple gives users the option to delete the Apple Music app, they should also give developers the ability to check if the app is installed.
The best solution I've got, though I expect there is something better out there, is to use MPMusicPlayer.prepareToPlay(completionHandler:) to check if there is an error when trying to play a track:
SKCloudServiceController().requestCapabilities { (capability:SKCloudServiceCapability, err:Error?) in
guard err == nil else {
print("error in capability check is \(err!)")
return
}
if capability.contains(SKCloudServiceCapability.musicCatalogPlayback) {
print("user has Apple Music subscription")
MPMusicPlayerController.systemMusicPlayer.setQueue(with: ["1108845248"])
systemMusicPlayer.prepareToPlay { (error) in
if error != nil && error!.localizedDescription == "The operation couldn’t be completed. (MPCPlayerRequestErrorDomain error 1.)" {
//It would appear that the user does not have the Apple Music App installed
}
}
}
if capability.contains(SKCloudServiceCapability.musicCatalogSubscriptionEligible) {
print("user does not have subscription")
}
}
I am not sure how this could apply to anybody using Apple Music within their app for anything other than playing tracks, but this seems to definitely work as a check when you are about to play a check. Whenever I am hit with that error, I simply create an alert telling the individual they have an Apple Music subscription but doesn't have the app installed.
Still, it would be great to be able to check without some completion handler as that would allow the boolean check to be integrated into conditional statements (via if capability.contains(SKCloudServiceCapability.musicCatalogPlayback) && hasAppleMusicAppInstalled { //do something }).
Luckily Apple provides you a method which returns false if no app installed on the device is registered to handle the URL’s scheme, or if you have not declared the URL’s scheme in your Info.plist file; otherwise, true.
func canOpenURL(_ url: URL) -> Bool
Following i'm posting the url schemes
Open = music://
Open = musics://
Open = audio-player-event://
Add the ones you will further use into your info.plist file.
After this use 'canOpenURL' to check
for more information check Apple docs
https://developer.apple.com/documentation/uikit/uiapplication/1622952-canopenurl
For the lucky souls that need music app installed to display MPMediaPickerController, the easiest way to check is to see if view was presented. If Music app is missing, it will fail silently.
let mediaPickerController = MPMediaPickerController(mediaTypes: MPMediaType.anyAudio)
mediaPickerController.delegate = self
mediaPickerController.prompt = "prompt"
presenter.present(mediaPickerController, animated: true, completion: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) { [weak self] () -> () in
if self?.presenter.presentedViewController == nil {
self?.callback(.failure(.failedToPresentMusicPickerError))
}
}
A possible solution is doing the following: Setup a developer token through the Apple Music API (Used so you can query Apple Music REST endpoints). Submit a request to the following StoreKit function (Documentation):
requestUserToken(forDeveloperToken:completionHandler:)
If your developer token is valid and the user token value returned is still nil/null then the device user is not a subscriber of the Apple Music service. An error that is generated with the HTTP status code is 401 (Unauthorized). This still requires you checking an error however does not require to try and play a specific track (Especially for some reason if the content track id your checking against becomes invalid or changed).
For the issue of account signed into the device and has a subscription but not the Music app downloaded: Handle the error upon attempting to play specific content and either provide information to the user or use content that does not require an Apple Music subscription as an alternative when an error occurs.
Yes, We can check most of the Applications by following these Steps:
Use the Deep URL or URL Scheme for the particular application you want to open, add that into info.plist
Use the same URL and Call this method
func canOpenURL(_ url: URL) -> Bool
let url = URL(string: "music://")
UIApplication.shared.open(url!) { (result) in
if result {
// The URL was delivered successfully!
}
}
You can use this property to detect if Apple Music is installed.
import MediaPlayer
var isAppleMusicInstalled: Bool {
get async {
await withCheckedContinuation { continuation in
MPMusicPlayerController.systemMusicPlayer.setQueue(with: ["1108845248"])
self.systemMusicPlayer.prepareToPlay { (error) in
if error != nil && error!.localizedDescription.contains("error 6") {
print("Apple Music App not installed")
continuation.resume(returning: false)
} else {
continuation.resume(returning: true)
}
}
}
}
}
Note that it triggers a permission dialog and that you need to add the NSAppleMusicUsageDescription key in your Info.plist with a value like "to check if Apple Music is installed".
Simply do: UIApplication.shared.canOpenUrl(URL(string: “music://”)!)
I'm currently thinking about implementing Firebase Auth to my Swift project, hence I've been reading some articles. - Namely among others this one.
I need some help understanding the given article. It's about "Authentication State Persistence". Does this mean, that if the value is set to local, the user will stay logged in even after closing the app? In other words, will he be able to sign up once and stay logged in until he decides to log out - even when he's offline?
Let's say a user decides not to create an account and logs in with "Anonymous Authentication" (I assume this is the type of login in this kind of case) - will he stay logged in forever as well or is there a danger of data loss, in case of going offline or closing the app?
First: the link you provided refers to a javascript firebase documentation
Second: the only thing available in IOS is you can create an anonymous user with
Auth.auth().signInAnonymously() { (authResult, error) in
// ...
let user = authResult.user
let isAnonymous = user.isAnonymous // true
let uid = user.uid
}
and you can convert it to a permanent user check This
Finally: whether the user is usual / anonymous , after you sign in you need to check this to show login/home screen every app open
if FIRAuth.auth()?.currentUser != nil {
print("user exists")
}
else {
print("No user")
}
and the user still exists unless you sign out regardless of whether you closed the app or not
If you are using the latest Firebase version, FIRAuth is now Auth:
if Auth.auth()?.currentUser != nil {
print("user exists")
}
else {
print("No user")
}
I need to access users Photos, for this I ask for permission. There are possible outcomes :
Permission granted : In this condition application resumes it normal functioning.
Permission Denied : In this case application shows an alert wherein user has option to goToSettings or to just ignore it. If user selects goToSettings and provides access to photos and comes back to application then it still says that permission is not granted. Permissions are only refreshed when I restart my application.
My Question: How to refresh the application's permission settings without restarting my application. Similar problem to my question is posted here.
Edit:
My application is a navigation controller based application and I check for access in my controller's viewDidLoad. I just tried if request permissions are refreshed if I pop and push the controller again. No luck, the results where same - it still said permission denied.
Edit 2 : Code to check for permissions
func requestAccess() -> Void {
PHPhotoLibrary.requestAuthorization {
status in
switch(status) {
case .notDetermined, .denied :
// perform relavent action
break
case .authorized , .restricted :
// perform relavent action
break
}
}
}
iOS kills your app when you changed privacy settings. And after next tap on app's icon your app is started from scratch. application:didFinishLaunching is called and so on. So you don't need to update permissions.
In your AppDelegate you could have logic in applicationDidBecomeActive to re-query the permission store for your updated permissions.
In your viewDidLoad for the view you check permissions on you could observe the notification like so;
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: #selector(yourClass.applicationDidBecomeActive(_:)),
name: UIApplicationDidBecomeActiveNotification,
object: nil)
The code below is Objective-C.
I think you can do this when user tapping a button or something:
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusNotDetermined) {
// ask for authorization
[PHPhotoLibrary requestAuthorization...
} else if (status == PHAuthorizationStatusAuthorized) {
// continue accessing photos
} else {
// access denied, go to settings if you want
}
No matter where I add code to check permissions for things like camera/mic/photos, the popup confirmation always kills my app or sends me back a few view controllers.
An example is as follows.
I have few view controllers in (part way through a registration process) when I have a page that deals with the permissions. Users tap a button to deal with the camera permission which uses the following code.
if AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo) != AVAuthorizationStatus.Authorized {
AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: { (granted :Bool) -> Void in
if granted == true {
// do something
} else {
// determine whether not determined, denied etc and do something else
}
});
}
However as soon as the iOS confirmation pops up, it throws the app back 2 view controllers. In other cases (e.g. on a viewDidLoad) permission requests kill the app as soon as the choice is made.
Any ideas what am I missing in my setup or how to prevent this behaviour?
Thanks.
I think you misunderstood my comment, what I did meant was
if AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo) != AVAuthorizationStatus.Authorized { // here you are checking if it's not authorized i..e it's denied, NotDetermined or Restricted
....
}
else if if AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo) == AVAuthorizationStatus.Authorized
// do the something in case it's autorized
I'm listing keys here -
<key>NSPhotoLibraryUsageDescription</key>
<string>This app requires access to the photo library.</string>
<key>NSCameraUsageDescription</key>
<string>This app requires access to the camera.</string>