9

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?

halfer
  • 18,701
  • 13
  • 79
  • 158
Emil Adz
  • 38,699
  • 35
  • 127
  • 177
  • Solution for any iOS version greater than 8.3 would be very much appreciated. Event if it only works for some versions. – Rasto Dec 17 '15 at 22:49

2 Answers2

2

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. Sceenshot 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

Julian E.
  • 4,501
  • 6
  • 30
  • 47
  • Well, this is half a solution at it's best. It's better then nothing yet this solution has some drawbacks. For starters this solution will work only after the first time you use the keyboard and if I'm not mistaken with allow full access granted. otherwise the keyboard won't be able to reach the shared NSUserDefaults. Next if the user will go to the settings and turn allow full access permissions off, you will have the wrong value at the application side, until the user will use your keyboard again.This is really not satisfactory but thanks for your effort and help. – Emil Adz Dec 19 '15 at 19:20
  • @Emil Adz Hm. I see. Well I'm sorry that you feel that way. I will try to find a better way and edit it in. – Julian E. Dec 19 '15 at 20:03
  • However I'd like to go to some points that you mentioned. In app groups, you can immediately share the NSUSerdefaults. You could without any problems implement a solution that will simply return the newest value every time the keyboard loads up, check if full access is granted or not and the return the value of true or false and update the NSUserdefault. This will be 5-8 lines of code at most and should be straightforward to check. Then if you update the NSUserdefaults you can also modify contents in your parent app. – Julian E. Dec 19 '15 at 20:07
  • I didn't really understand how your comment answer any of the two issues I raised with your solution. – Emil Adz Dec 19 '15 at 20:10
  • Well, sorry. I thought that I had expressed myself in clear English and easily understandable points. Sorry for that. What I am trying to say is that NSUserdefaults can be written to and accessed immediately when the keyboard runs, no need for the allowance of the full access. I wanted to use your code to show you how you can access the returned value of true or false in your container app. You stated that if you are not mistaken the app needs to receive full access to be able to access the NSUserdefaults. You are mistaken, any extension can access the NSUserdefaults placed in the app group – Julian E. Dec 19 '15 at 20:17
  • without any further permissions needed. – Julian E. Dec 19 '15 at 20:17
  • My second point was that you can simply call the function that returns true or false every time the keyboard opens for example. You decide when to call it, and by adding the code to save to the NSUserdefaults, you will always have the newest value. You can for example call it every time the keyboard loads up. – Julian E. Dec 19 '15 at 20:19
  • You will have the wrong value until the user uses your keyboard again, but there is no other way of updating those values without the keyboard being used. – Julian E. Dec 19 '15 at 20:20
  • Well, currently I'm not working on this iPhone project so I had not way to test the allow full access and NSUserdefaults statement. Yet this does not solved any of the 2 issues. The value will be empty until your first use of the keyboard. and it will be wrong until the first time you use your keyboard after the settings change. – Emil Adz Dec 19 '15 at 20:21
  • This is a workaround, not perfect but to my knowledge the only way to go about it. You can simply prompt the user to allow full keyboard access like they do in the Swift Keyboard app. Other than that there isn't really a better way of checking as this information is exclusive to the keyboard. I did submit a ticket to tech support to find out more for you, but it appears that this is the closest you can get. – Julian E. Dec 19 '15 at 20:22
  • You will have to assume it is false until the keyboard is used the first time, and why not just prompt the user to allow the full access like they do in other apps? – Julian E. Dec 19 '15 at 20:24
  • Sorry if it this answer didn't meat your expectations, but it's the best you can get to this info as far as I know. Sorry and I'll let you know what DTS says – Julian E. Dec 19 '15 at 20:26
  • Well we do prompt him, but I think and so did my bosses that it isn't enough. For the record this is a whole other issue, those questions actually already have nothing to do with the question at hand. – Emil Adz Dec 19 '15 at 20:26
  • I do realize that. I just fear that this is the most you can do as many of the big keyboard apps don't do much else than to also just prompt the user to switch in on. Sorry I couldn't help you more than "half a solution at best" – Julian E. Dec 19 '15 at 20:27
  • I'm sorry if you were offended by this statement. It wasn't my attention. – Emil Adz Dec 19 '15 at 23:01
  • No no, I'll try my best to find out more for you and let you know as soon as possible. Talk soon! – Julian E. Dec 19 '15 at 23:27
  • Thanks again for your effort, here is a +1 for it. – Emil Adz Dec 20 '15 at 08:48
  • @EmilAdz I updated the answer with info that came back from Apple's DTS. Hope it helps you more now... – Julian E. Dec 22 '15 at 05:13
  • Please update with proper steps, it is not working any more as mentioned – Sandip Patel - SM Dec 14 '16 at 12:15
0

You can easily test whether the "Allow Full Access" permission is granted on iOS 11 and later.

  1. To get the "Allow Full Access" permission, first subclass the UIInputViewController class.
  2. 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