My app keep deny the access to contacts iOS - Swift - ios

I have a view when it get loaded it will check first the permission to access the contacts if it's Authorized, NotDetermined or Denied .. the code at first time will go with NotDetermined so it will call function to ask for access .. the problem is here in this function :
private func requestContactsAccess() {
//store = CNContactStore()
store.requestAccessForEntityType(.Contacts) {granted, error in
if granted {
dispatch_async(dispatch_get_main_queue()) {
self.accessGrantedForContacts()
return
}
}
}
}
Now the app never ask for access to Contacts , I don't know why, it will select the permission as denied by its self .
I don't know if the problem with the code or the simulator because this work for other people .
Note : when I go to the settings of the sim , Setteings > Privacy > Contacts .. I find nothing ! just saying : 'Applications that have requested access to your contacts will appear here' . which mean the app never ask for it !
Any help ?

I'm not sure if this is your problem but if you're running your app on iOS 10 Simulator you need to provide a "usage description" for accessing private information like Contacts (camera, camera roll, etc.).
Open your Info.plist and add a new entry and you will see new "Privacy - ..." settings.
Select "Privacy - Contacts Usage Description" and type in a usage description. See if this helps.
When run you should see the grant access popup with your usage description.

First time when code executed, popup appears for permission of accessing contact list. Which button you tapped on that popup? (Allow or Don't Allow) ?
I think you have unintentionally tapped don't allow. Please go to Settings -> -> Allow to access Contacts -> Set switch to YES.

Related

ReplayKit Broadcast upload extension - Service not found

I'm working on an IOS swift application that will allow the user to record the entire screen, any app and even the home screen.
In order to do that, I added a Broadcast Upload Extension to my app.
First I used the RPSystemBroadcastPickerView class in order to add a record button to my view that allow the user to open the record popup and select to which app he wants to broadcast the screen flow. And it's working fine :
But I would like to avoid this step and directly open the popup when the app launch.
So I wrote the following code to do that :
RPBroadcastActivityViewController.load(withPreferredExtension: "ch.jroueche.RecordApp.TestScreen", handler: {broadcastAVC,error in
guard error == nil else {
print("Cannot load Broadcast Activity View Controller.")
return
}
if let broadcastAVC = broadcastAVC {
broadcastAVC.delegate = self
self.present(broadcastAVC, animated: true, completion: {
// broadcastactivityviewcontroller will perform the callback when the broadcast starts (or fails)
print("I've START")
})
}
})
Unlikeenter code here the RPSystemBroadcastPickerView solution, I'm getting the following error :
The preferred broadcast service could not be found.
My issue is similar to the following post :
App not showing up as a broadcast service in RPBroadcastActivityViewController
I also added the extension and the preferred extension identifier is correct.
Why would it be possible using the RPSystemBroadcastPickerView and not programmatically using RPBroadcastActivityViewControllerclass. That does not make sense for me.
Does someone have an idea of what could be the issue and how could I fix it ? Or a workaround in order to do this screen record.
Thanks in advance
It appears that RPBroadcastActivityViewController shows ONLY Broadcast Setup UI Extension, while RPSystemBroadcastPickerView shows ONLY Broadcast Upload Extension. But I have no idea why, as both of them are stated to show list of available providers/services.
It would be very helpful if someone could bring more details on the topic.

Geolocation.requestPermission() only works once

I have an app that needs to request permanent access to geolocation permission ( also in the background ) to gather data.
At the apps start I do a permission check like so ( simplified )
private static function check():void{
if (Geolocation.permissionStatus == PermissionStatus.GRANTED){
onPermGranted();
}else{
_geo = new Geolocation();
_geo.addEventListener(PermissionEvent.PERMISSION_STATUS, onPermission );
try {
_geo.locationAlwaysUsePermission = true;
_geo.requestPermission();
} catch(e:Error){
onError(e);
}
}
};
private static function onPermission(e:PermissionEvent):void{
trace("GeolocationUtil::onPermission: "+e.status);
};
The first time the app starts and this gets called and works.
Now if I quit the app, then change the permission to "never", and restart the app, I can see that
_geo.requestPermission();
gets called, but there is no response whatsoever and I do not get the iOS permissions dialog as well.
Any ideas? Thanks a lot!
The system will only ask once for the permission even if you uninstall your app and reinstall it again, looks like it has a system level cache,
Try go to Setting -> General -> Reset -> Reset Location & Privacy

iOS 11.4 not asking Privacy Usage ( Privacy - Motion Usage Description has been set )

I'm stumped, iOS 11.4 ( 15F79 ), iPhone 6. Cannot get the App to Ask for Motion Data. info.plist has been set via the editor and double checked via the info.plist open in textWrangler, Also deleted key and saved via textWrangler.
<key>NSMotionUsageDescription</key>
<string>This app needs your Phones motion manager to update when the phone is tilted. Please allow this App to use your phones tilt devices</string>
I have deleted then reinstalled the app about 10 times. I have restared the phone 5 times. I have checked through settings and my app does NOT show up in Privacy-Motion and Fitness or anywhere else in settings. I am using a free developer account, maybe that has something to do with it?
I created a new Xcode game template and changed nothing apart from importing CoreMotion and this code
**** Edited, sorry I forgot to say I had started the instance, just forgot to put it here, just in case someone thinks that's the problem ************
let motionManager = CMMotionManager()
override func didMove(to view: SKView) {
motionManager.startDeviceMotionUpdates()
if motionManager.isDeviceMotionActive == true {
motionManager.accelerometerUpdateInterval = 0.2
motionManager.startAccelerometerUpdates(to: OperationQueue.current!, withHandler: {
(accelerometerData: CMAccelerometerData!, error: NSError!) in
let acceleration = accelerometerData.acceleration
print(accelerometerData)
} as! CMAccelerometerHandler)
}else{
print(CMMotionActivityManager.authorizationStatus().rawValue)
}
which prints a 0 ( an Enum - case not determined ) to the console.
In my actual app it was a 3 ( same Enum - case Denied ).
As I've said, I have uninstalled, reinstalled, edited plist via Xcode and text wrangler ( a code editor ) , tried different versions of the code above, tried the code in different places ( in did move to view, in class )tried code off apple docs. etc.... I haven't been asked the NSUsage question and the App keeps crashing.
I have looked for ways to get the Alert fired up, As in CLLocationManager.requestWhenInUseAuthorization() but I cannot find a comparable CMMotion version ( I don't think there is one. ) I have created a new swift file , imported Foundation and CMMotion and just put that code there, But still no Alert asking for Motion Data.
I tried a single view app template instead of a game template thinking that might be the issue, Nope.
What do I do?
Any help Appreciated. Thanks
You are confusing two related but different classes.
CMMotionManager gives access to accelerometer, magnetometer and gyroscope data. It does not require any user permission as this information is not considered privacy related.
In your else clause you are checking the authorisation status of CMMotionActivityManager. This object reports the device motion type (walking, running, driving). This information is considered privacy related and when you create an instance of this class and request data from it, the permissions alert is displayed.
The reason your else is being triggered is because you are checking isDeviceMotionActive; this will be false until you call startDeviceMotionUpdates, which you never do. Even if you used isAccelerometerActive you would have a problem because you call startAccelerometerUpdates in the if clause which will never be reached.
You probably meant to check isAccelerometerAvailable. If this returns false then there isn't much you can do; the device doesn't have an accelerometer.
Update
It doesn't make sense to check isDeviceMotionActive immediately after calling startDeviceMotion:
You know it's active; you just started it
I imagine the start up takes some time, so you could expect to get false if you check immediately.
Apple recommends that you do not have more than one observer in place for each motion device type, so the purpose of check the is...Active to ensure you don't call start... again if you have already done so.
If you only want gyroscope data then you don't need to call startDeviceMotionUpdates at all.

What makes a user discoverable to CKDiscoverAllUserIdentitiesOperation?

I am trying to discover contacts for a user with the code below (the code is in an implementation of a UITableViewController. I put breakpoints in both code blocks, and I determined that the the userIdentityDiscoveredBlock is not called while the completionBlock is called. This indicates that the operation is being run as expected, it just isn't finding any contacts.
I am running on the simulator, but I verified that the simulator has synced all my iCloud contacts (opening the Contacts app on the simulator shows all my contacts).
override func viewDidLoad() {
super.viewDidLoad()
let op = CKDiscoverAllUserIdentitiesOperation()
op.discoverAllUserIdentitiesCompletionBlock = { error -> Void in
// reload my data table
}
op.userIdentityDiscoveredBlock = { user -> Void in
if user.hasiCloudAccount {
self.iCloudUsers.append(user)
} else {
self.nonICloudUsers.append(user)
}
}
CKContainer.default().add(op)
}
So my question is this - Is there something else that has to be done in order to discover contacts? Is this a simulator issue?
I searched the documentation and other questions but I can't seem to find information on this given the operation is new to iOS 10.
There's quite a bit that must be done before CKDiscoverAllUserIdentitiesOperation will return any results.
First, each user of your app must grant permission to be looked up by email. Your app makes this request using CKContainer requestApplicationPermission.
Each user of your app must also be logged into an iCloud account. iCloud Drive must also be enabled by the user.
And lastly, for CKDiscoverAllUserIdentitiesOperation to return any users, the person must have contacts with email addresses that match other users that completed all of the previous steps.

How to test if "Allow Full Access" permission is granted from containing app?

I'm working on a keyboard extension project. At some points of the application code I need to test if the user have granted the "Allow Full Access" permission for the keyboard extension. The deal is that I need to do those tests from the application side, and based on this let the user to access keyboard settings or alert him in case the permission wasn't granted.
The problem is that the methods that provided here like:
func isOpenAccessGranted() -> Bool {
return UIPasteboard.generalPasteboard().isKindOfClass(UIPasteboard)
}
or:
func isOpenAccessGranted() -> Bool {
let fm = NSFileManager.defaultManager()
let containerPath = fm.containerURLForSecurityApplicationGroupIdentifier(
"group.com.example")?.path
var error: NSError?
fm.contentsOfDirectoryAtPath(containerPath!, error: &error)
if (error != nil) {
NSLog("Full Access: Off")
return false
}
NSLog("Full Access: On");
return true
}
Working only from the keyboard side, as the keyboard is the only one that is affected from this permission. From the containing app side both of those methods always return true.
Does someone knows a reliable way to test this from the application side?
Consider using NSUSerdefaults in your app and keyboard. In order for an extension and app to be able to share the same NSUserdefaults, you can simply turn on App Groups. Select your main app target under your project in the project navigator and go to capabilities and enable App Groups by toggling it to on, adding your Developer profile and fixing the possibly arising issues.
Now create a new container. According to the help, it must start with “group.”, so give it a name like “group.com.mycompany.myapp”. Select your Today Extension target and repeat this process of switching on app groups. Don’t create a new one, rather select this newly created group to signify that the Today Extension is a part of the group.
This will now allow you to share the same NSUserdefaults as your container app.
All you have to do now is use the code you provided and add the saving method to the NSUserdefaults like so:
func isOpenAccessGranted() -> Bool {
let defaults = NSUserDefaults.standardUserDefaults()
let fm = NSFileManager.defaultManager()
let containerPath = fm.containerURLForSecurityApplicationGroupIdentifier(
"group.com.example")?.path
var error: NSError?
fm.contentsOfDirectoryAtPath(containerPath!, error: &error)
if (error != nil) {
NSLog("Full Access: Off")
defaults.setBool(false, forKey: "hasFullAccess")
return false
}
NSLog("Full Access: On");
defaults.setBool(true, forKey: "hasFullAccess")
return true
}
Do this in your keyboard extension. And then in your parent app, simply retrieve them and act upon their value.
let hasFullAccess : Bool = NSUserDefaults.standardUserDefaults().boolForKey("hasFullAccess")
if hasFullAccess{
//User granted full access
}
else{
//User didn't grant full access
}
If the user didn't grant full access the show an alert, else code away!
EDIT:
After contacting Apple's Technical Developer support they told me that this is not possible to achieve in any supported way as of right now. Their response is below:
Our engineers have reviewed your request and have concluded that there
is no supported way to achieve the desired functionality given the
currently shipping system configurations.
If you would like for Apple to consider adding support for such
features in the future, please submit an enhancement request via the
Bug Reporter tool at https://developer.apple.com/bug-reporting/.
Hope that helps, Julian
You can easily test whether the "Allow Full Access" permission is granted on iOS 11 and later.
To get the "Allow Full Access" permission, first subclass the
UIInputViewController class.
Add the code. The code returns a bool value.
Objective-C
[self hasFullAccess];
Swift
self.hasFullAccess
https://developer.apple.com/documentation/uikit/uiinputviewcontroller/2875763-hasfullaccess?changes=_2
Objective-C
[UIInputViewController new].hasFullAccess;

Resources