EKEventStore request access not working - ios

var eventStore: EKEventStore?
#IBAction func bbbbbbb(sender: UIButton) {
if eventStore == nil {
eventStore = EKEventStore()
}
self.eventStore?.requestAccessToEntityType(EKEntityType.Event, completion: { (aBool, error) -> Void in
print(error, aBool)
})
}
the print is nil, false always... Its behaving like the user has already denied access, but the promt is never being showed. The same code of course works in a new blank app on the same devices. Things I have tried: resting setting on device, simulator and using a new device where the app has never been installed and of course cleaning the project, but with no success. Plus in the app settings the calendar permission is not showing as well. Any ideas of what is going on?

With iOS 10, you need to add the following key in your plist to allow an app to access the calendar (if not, the app will simply crash when requesting access):
key: "Privacy - Calendars Usage Description"
value: "$(PRODUCT_NAME) calendar events"
see here:
https://iosdevcenters.blogspot.com/2016/09/infoplist-privacy-settings-in-ios-10.html

Try the following code
let eventStore = EKEventStore()
eventStore.requestAccessToEntityType(EKEntityType.Event) { (granted: Bool, error: NSError?) -> Void in
if granted{
print("Got access")
let defaultCalendar = eventStore.defaultCalendarForNewEvents
print("\(defaultCalendar.calendarIdentifier)")
}else{
print("The app is not permitted to access reminders, make sure to grant permission in the settings and try again")
}
}

Related

Unable to bypass error code 4 when using HealthKit through the simulator

I'm creating a new multiplatform app using the Xcode beta run on macOS Ventura beta. I want to use HealthKit to submit mindfulness minutes but I can't get it working. I created a new app with JUST this and I have the same issue so I came here hoping someone knows how to fix it.
The ContentView for the app is:
import SwiftUI
import HealthKit
struct ContentView: View {
// You need only a single HealthKit store per app. These are long-lived objects; you create the store once, and keep a reference for later use.
let myHealthStore = HKHealthStore()
let typestoRead = Set([HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier.mindfulSession)!])
let mindfulType = HKObjectType.categoryType(forIdentifier: .mindfulSession)
#State var message: String?
var body: some View {
NavigationView {
if HKHealthStore.isHealthDataAvailable() {
Text("Health Data Available")
} else {
Text("Health Data NOT Available")
}
Button(action: {
print("Setting 1 minute Mindfulness")
let startTime = Date()
let endTime = startTime.addingTimeInterval(2.0 * 60.0)
print("From \(startTime) until \(endTime).")
// Create a mindful session with the given start and end time
let mindfullSample = HKCategorySample(type:mindfulType!, value: 0, start: startTime, end: endTime)
// Save it to the health store
myHealthStore.save(mindfullSample, withCompletion: { (success, error) -> Void in
print("in completion")
if error != nil {
print("error: \(error!)")
message = "Failure: \(error!)"
return
}
print("New data was saved in HealthKit: \(success)")
message = "Success: \(success)"
})
}, label: {
Text("Set 1 Minute Mindfulness")
})
.buttonStyle(.bordered)
Divider()
Text(message ?? "No Message.... yet")
}
.onAppear() {
print("ContentView appears")
myHealthStore.requestAuthorization(toShare: [], read: typestoRead) { (success, error) -> Void in
if(success){
// Read or write the HealthKit data
print("success: \(success)")
}
else{
// Authorization failure
print("error: \(error!)")
}
}
}
}
}
Additionally I went to Application, Target, Info, and pressed the plus sign to add the following PLIST values:
Privacy - Health Records Usage Description
Privacy - Health Update Usage Description
Privacy - Health Share Usage Description
I also went to Application > Target > Signing & Capabilities > and pressed the plus to add HealthKit and check off Background Delivery.
This got me past the first error but now when I run it I either get an error code 1 or 4. One is understandable, when run on my iPad or Mac as apparently Health data is unavailable on this device but, when run on the iOS simulator I don't understand how to get past the error:
Error Domain=com.apple.healthkit Code=4 "Missing application-identifier entitlement" UserInfo={NSLocalizedDescription=Missing application-identifier entitlement}
What am I missing? I looked online but most people with this error seem to be updating an app. This is a newly created app. Just in case I've uninstalled it and reinstalled it on the simulator, chose a different simulator, and created a new bare bones app. Any tips to access HealthKit?
Please confirm that there is a bundle id string listed in the entitlements plist for the application-identifier key? Error Code 4 is referring to that missing.

TouchID authentication inside Siri Intent Extension

I have an Intent Extension with the View category that is working pretty good for showing an app info.
Now I need to enable TouchID for security reasons, so the user needs to authenticate before requesting the info.
I tried this:
func handle(intent: GetSaldoIntent, completion: #escaping (GetSaldoIntentResponse) -> Void) {
let myContext = LAContext()
myContext.evaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
localizedReason: "Unlock to see the info",
reply: { [unowned self] (success, error) -> Void in
if( success ) {
completion(GetSaldoIntentResponse.success(saldo: String(self.paymentProvider.balance)))
return
}
})
completion(GetSaldoIntentResponse(code: .failureRequiringAppLaunch, userActivity: nil))
}
}
But the TouchID dialog closes the Siri screen and then the conversation ends:
Is there a way to request for TouchId validation inside an Intent Extension?
I know PKPayment do something similar, but this isn't a transaction so I can't use ApplePay.
Siri already supports the authorisation, you just need to let Siri know that your intent requires authorisation rather implementing authorisation yourself. Hope that helps you:
https://developer.apple.com/documentation/sirikit/requesting_authorization_to_use_sirikit

Why is admob consent form not loading on actual devices?

I am trying to implement Admob for my iOS app. The form loads on the Xcode simulator devices. I am located in the US, but I have used the following code to test that the Consent SDK is working for European users. When I use this with a simulator, the form and ads load.
PACConsentInformation.sharedInstance.debugIdentifiers = ["SPECIFIC_TO_MY_DEVICE"]
PACConsentInformation.sharedInstance.debugGeography = PACDebugGeography.EEA
The form does not load on my physical device with this configuration. The form also did not load when I used testflight to distribute a test version to a test user in the EU. Subsequently, the ads did not load on "European" devices.
When the form should load, I get an error from the below block of code. Also. I get the error WebKitDomain Error 101. My ATS settings are set up in the plist per the Admob documentation.
thisForm.load {(_ error: Error?) -> Void in
if let error = error {
print("Error loading form: \(error.localizedDescription)")
//I am getting the error here.
} else {
thisForm.present(from: self) { (error, userPrefersAdFree) in
print("in present handler")
if let error = error {
// Handle error.
print("error presenting: \(error.localizedDescription)")
} else if userPrefersAdFree {
//TODO: find a way to disable ads
} else {
// Check the user's consent choice.
//let status = PACConsentInformation.sharedInstance.consentStatus
}
}
}
Does anyone know what may be causing these errors with physical devices? I have tried with a real ad id and a test ad id.
Present consent form only if the following equals true
If requestLocationInEEAOrUnknown == true {
//present consent form
}
else {
//do whatever is needed
}

Realm Object Server refuses to recognize permission and loads objects extremely slow

I have a synchronized realm running on Realm Object Server. It is a global realm created by the admin user. I created another user on the server (not an admin) and used the admin user to grant read-only permissions to that user for that particular realm.
I can see the permission when I query the admin's management realm and the normal user's permission realm. However, when I connect to the global realm from my iOS app (Swift 3) with the normal user, the server returns error code 206: permission denied and closes the realm file.
The strange thing is that the app manages to download a few objects from the realm, and it also loads a few more objects (about 3) every time I relaunch it.
An even stranger thing is that when I launch the app with the admin user the same thing happens except it loads about 100 extra objects in every relaunch and it doesn't show the permission denied error.
Note: I'm getting these results on the iOS simulator and still haven't tried the app on an actual device.
UPDATE: I have tried the app on a physical device and the problem persists.
I'm using Realm Swift v2.10.1 on Xcode 8.3.3 and Realm Object Server v1.8.3 on a Linux Ubuntu 16.04.3 x64 machine.
EDIT:
Here is how I apply the permission:
let per = SyncPermissionValue(realmPath: "/realmname", userID: "userId", accessLevel: .read)
realmUser!.applyPermission(per, callback: { (error) in
print("PERMISSION ERROR: \(String(describing: error))")
if error == nil {
print("no error")
}
})
Here is how connect from my app. These methods are in a custom class which is used by the view controller requesting the objects from the realm.
private func logInToServer() {
SyncUser.logIn(with: .usernamePassword(username: "username", password: "pass", register: false), server: URL(string: "http://server IP:9080")!, onCompletion: { (user, error) in
var realmUser = user
if realmUser == nil {
realmUser = SyncUser.current
}
self.connectToDatabase(realmUser: realmUser!)
})
} // end logInToServer()
private func connectToDatabase(realmUser: SyncUser) {
DispatchQueue.main.async(execute: {
let configuration = Realm.Configuration(syncConfiguration: SyncConfiguration(user: realmUser, realmURL: URL(string: "realm://server IP/realmname")!))
self.realm = try! Realm(configuration: configuration)
// I initially found out that implementing a small delay gave the app enough time to download all objects even though the permission denied error was still there. But, this no longer works.
Timer.scheduledTimer(timeInterval: self.delay, target: self, selector: #selector(self.populateResults), userInfo: nil, repeats: false)
})
} // end connectToDatabase()
#objc private func populateResults() {
self.categories = self.realm.objects(BookCategory.self)
self.books = self.realm.objects(Book.self)
delegate?.didPopulteResults(categories, books) // The delegate is the view controller requesting the objects.
}

Set a reminder in iOS Swift

I am trying to set a simple EKReminder in my swift application to remind users to catch the bus. However, when I try to save my reminder, I always get a error (no error is reported, the app just crashes). I have the code below.
public class func createReminder(reminderTitle: String, timeInterval: NSDate) {
var calendarDatabase = EKEventStore()
calendarDatabase.requestAccessToEntityType(EKEntityTypeReminder,
completion: nil)
let reminder = EKReminder(eventStore: calendarDatabase)
reminder.title = reminderTitle
let alarm = EKAlarm(absoluteDate: timeInterval)
reminder.addAlarm(alarm)
reminder.calendar = calendarDatabase.defaultCalendarForNewReminders()
var error: NSError?
calendarDatabase.saveReminder(reminder, commit: true, error: &error)
}
The following should work in Swift 4.2
func AddReminder() {
eventStore.requestAccess(to: EKEntityType.reminder, completion: {
granted, error in
if (granted) && (error == nil) {
print("granted \(granted)")
let reminder:EKReminder = EKReminder(eventStore: self.eventStore)
reminder.title = "Must do this!"
reminder.priority = 2
// How to show completed
//reminder.completionDate = Date()
reminder.notes = "...this is a note"
let alarmTime = Date().addingTimeInterval(1*60*24*3)
let alarm = EKAlarm(absoluteDate: alarmTime)
reminder.addAlarm(alarm)
reminder.calendar = self.eventStore.defaultCalendarForNewReminders()
do {
try self.eventStore.save(reminder, commit: true)
} catch {
print("Cannot save")
return
}
print("Reminder saved")
}
})
}
info.plist requires appropriate privacy settings as well.
I haven't used anything like this before, but looking at your code I can see that you call the requestAccessToEntity-method, without handling the response. That method will most likely show the user a prompt, asking them to accept that your app has access to "Reminders". With your code, you ask for the permission, but the rest of your code will execute immediately after asking, without 'waiting' for the response. The very first time this code runs, the user will be asked, and your reminder will be denied, because it tries to save right away.
Even if your user clicks "allow", your code has already run without permission.
Now, if the user clicked allow one time, and then tries to do the same again, then maybe it will work, I don't know. But if your user clicked "Cancel" on the prompt, your code will never work until they go into Settings and allow your app to show reminders.
You should not create your reminder before you know if the user allows it, so you should really split this function into two separate functions. And do not pass nil for completion in that function; handle the response.
try the following:
EKEntityTypeReminder -> EKEntityType.Reminder

Resources