Grant access to NAB programatically on iOS 7.0 Simulator
Asked Answered
A

2

6

Is it possible to grant access to the native address book (NAB) on iOS 7.0 Simulator programmatically? I am writing xctest Unit Tests that need write access to NAB. The unit tests are run on iOS 7.0 Simulator and are part of Continuous Integration process and doesn't involve any user interaction.

Currently unless the user grants access explicitly via the “TestApp” Would like to Access Your Contacts alert, access to NAB is denied.

Autohypnosis answered 30/6, 2014 at 18:56 Comment(1)
iOS 8 version of this question: https://mcmap.net/q/1775312/-manipulate-app-permissions-on-ios-8-simulator/476716Individualism
A
7

In the spirit of sharing I am going to answer my own question. Among other permissions, Address Book access permission is stored in TCC.db database that is located in /Library/TCC/ in the iPhone Simulator folder.

e.g. /Users/useriko/Library/Application Support/iPhone Simulator/7.1-64/Applications/[appGUID]/Library/TCC/TCC.db

Permissions are stored in the access table in TCC.db database. access table schema is: TCC.db schema

The fields we are interested in are:

  1. service - the permission type
  2. client   - the app identifier
  3. allowed - permission granted?

In order to grant Access Book permission, and appropriate record should be inserted into the access table (or updated if already exists). After the record was either inserted or updated the table should look like that: access table after update

I've wrote the following method to update the TCC.db database.

#import <sqlite3.h>

- (void)grantAccessBookAccess {
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  // tccDbPath: /Users/useriko/Library/Application Support/iPhone Simulator/7.1-64/Applications/FB8DF5E9-94B8-4CA9-A167-43AFE794B94E/Document

  NSString *tccDbPath = nil;
  tccDbPath = [[[[paths objectAtIndex:0]
                  stringByDeletingLastPathComponent]  // remove Document
                  stringByDeletingLastPathComponent]  // remove [appGUID]
                  stringByDeletingLastPathComponent]; // remove Applications

  // tccDbPath: /Users/useriko/Library/Application Support/iPhone Simulator/7.1-64/

  tccDbPath = [[[tccDbPath stringByAppendingPathComponent:@"Library"]
                stringByAppendingPathComponent:@"TCC"]
                stringByAppendingPathComponent:@"TCC.db"];

  // tccDbPath: /Users/useriko/Library/Application Support/iPhone Simulator/7.1-64/Library/TCC/TCC.db

  sqlite3 *database;
  if(sqlite3_open([tccDbPath UTF8String], &database) != SQLITE_OK) {
    NSLog(@"Error while opening database. %s", sqlite3_errmsg(database));
    return;
  }

  NSString *updateSql = @"INSERT OR REPLACE INTO access (service, client, client_type, allowed, prompt_count) VALUES (\"kTCCServiceAddressBook\",\"com.your.app.id\",0,1,1);";

  int rc;
  char* errmsg;
  const char *sql = [updateSql UTF8String];
  rc = sqlite3_exec(database, sql, NULL, NULL, &errmsg);
  if (rc != SQLITE_OK) {
    NSLog(@"Error updating access table. %s", errmsg);
    sqlite3_free(errmsg);
  }

  sqlite3_close(database);
}

Because of the obvious reasons, the target should be linked with libsqlite3.dylib.

DO NOT forget to change the app identifier (com.your.app.id) in the updateSql to your app identifier.

Autohypnosis answered 4/7, 2014 at 21:8 Comment(2)
any ideas how to do it in swift3 ?Denverdeny
@Async Sorry. No idea.Autohypnosis
B
1

This Cocoapod works great for testing purposes: https://github.com/plu/JPSimulatorHacks

Brocklin answered 25/8, 2015 at 18:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.