How do I update Xcode codes I can use iOS 14 functions? - firebase

I was watching a tutorial on how to fetch user location in swift and I had a problem here:
class teste: CLLocationManager, CLLocationManagerDelegate{
#Published var lctionManager = CLLocationManager()
func locationManagerDidChangeAuthorization (_ manager: CLLocationManagerDelegate){
switch manager.authorizationStatus {
case .authorizedWhenInUse:
print("authorized")
case .denied:
print("denied")
default:
print("unkown")
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error){
print(error.localizedDescription)
}
}
The error was a in locationManagerDiChangeAuthorization (Instance method 'locationManagerDidChangeAuthorization' nearly matches optional requirement 'locationManagerDidChangeAuthorizantion' of protocol 'locationManagerDelegate') and in manager.authorizationStatus( Value of type 'CLLocationManagerDelegate' has no member 'authoizationStatus')
After some research, I found out that these are iOS 14 only, and my code may be written in iOS13 (actually, for some codes, I have to add #available(iOS 14.0, *) to make them work, but this time it didnt seem it work).
But, as a beginner, I don't know how to update my code (searched for some stuff but nothing caught my eyes). How do I update my code? Would it interfere in anything? Is it necessary or its better to write something to integrate both iOS 14 and 13?

Project -> Info -> iOS Deployment Target
here you can change deployment target to iOS 14.

Related

watchOS 9 WidgetKit complications missing com.apple.developer.healthkit entitlement

I have an iOS/wOS app that launched last year. Now I want to add complications to it and use the new way of doing complications with WidgetKit. I have everything in place up to the point where I'm supposed to read the data from Health to display it, where it fails with Missing com.apple.developer.healthkit entitlement.
This is the new extension I've added
It's embedded in the WatchKit app NOT in the WatchKit Extension and I've added permission to read health data directly in the info.plist for the extension
I pull the data from the TimelineProvider protocol method
func getTimeline(in context: Context, completion: #escaping (Timeline<Entry>) -> ()) {
let currentDate = Date()
var entries: [WorkoutEntry] = []
ComplicationHealthManager.loadPreviousWorkouts { workout in
let workoutEntry = WorkoutEntry(date: currentDate, workout: workout)
entries.append(workoutEntry)
let timeline = Timeline(entries: entries, policy: .after(currentDate))
completion(timeline)
}
}
with the help of a small manager class
class ComplicationHealthManager: ObservableObject {
static func loadPreviousWorkouts(completion: #escaping (HKWorkout?) -> Void) {
let healthStore: HKHealthStore = HKHealthStore()
let workoutPredicate = HKQuery.predicateForWorkouts(with: .traditionalStrengthTraining)
let compound = NSCompoundPredicate(andPredicateWithSubpredicates:
[workoutPredicate])
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate,
ascending: false)
let query = HKSampleQuery(
sampleType: .workoutType(),
predicate: compound,
limit: 0,
sortDescriptors: [sortDescriptor]) { (query, samples, error) in
guard
let samples = samples as? [HKWorkout],
error == nil
else {
completion(nil)
return
}
let calendar = Calendar.current
let todaysSamples = samples.filter{ calendar.isDateInToday($0.endDate) }.last
completion(todaysSamples)
}
healthStore.execute(query)
}
}
The issue is in the closure for the health query where it returns with no workouts but an error stating
Error Domain=com.apple.healthkit Code=4 "Missing com.apple.developer.healthkit entitlement." UserInfo={NSLocalizedDescription=Missing com.apple.developer.healthkit entitlement.}
The problem here is I don't understand where and how to add an entitlement for the complication extension or the WatchKit app, as none of them have the option for health. I have a health entitlements set for the iPhone app and the WatchKit Extension.
I found the problem to be that I had the old implementation of watchkit apps, with both a Watch app and a Watch extension. That was the problem. I went and used the migration from Xcode 14 to merge the Watch App and Extension into a new watch app and everything works now.
Please file a Feedback at feedback.apple.com for this.
You can manually add the HealthKit entitlement to the Code Signing Entitlements file (create a new one if there isn't one already) associated with the target
<key>com.apple.developer.healthkit</key>
<true/>

SkypeSDK Video and audio issue - mediaRelayAccessToken not found

I'm having problems with adding an audio or a video service to a coversation.
The chat service works fine for me.
When I add a video or an audio service I get following error:
Error: GET /ucwa/oauth/v1/applications/113925534802/communication/mediaRelayAccessToken failed: 404
{
[functions]: ,
__proto__: { },
code: "RequestFailed",
description: "GET /ucwa/oauth/v1/applications/113925534802/communication/mediaRelayAccessToken failed: 404",
message: "GET /ucwa/oauth/v1/applications/113925534802/communication/mediaRelayAccessToken failed: 404",
name: "Error",
req: { },
rsp: { },
stack: "Error: GET /ucwa/oauth/v1/applications/113925534802/communication/mediaRelayAccessToken failed: 404
at process (https://swx.cdn.skype.com/build2015/v5/SDK-build.js:8079:29)
at Anonymous function (https://swx.cdn.skype.com/build2015/v5/SDK-build.js:8018:29)
at Anonymous function (https://swx.cdn.skype.com/build2015/v5/SDK-build.js:1714:25)
at map (https://swx.cdn.skype.com/build2015/v5/SDK-build.js:1331:25)
at decompose (https://swx.cdn.skype.com/build2015/v5/SDK-build.js:8017:25)
at Anonymous function (https://swx.cdn.skype.com/build2015/v5/SDK-build.js:8007:29)
at handle (https://swx.cdn.skype.com/build2015/v5/SDK-build.js:2220:33)
at Anonymous function (https://swx.cdn.skype.com/build2015/v5/SDK-build.js:698:25)"
}
The Skype For Business Plugin is installed and works fine.
A Skype Edge server is currently not installed.
I'm using Internet Explorer 11.
The error occurs with the Skype Web SDK On Prem Sample from Microsoft as well as on my own website.
When I try to add video or audio for the second time to the same conversation i dont get any error message at all, but it still doesn't work. The request doesnt show up in the dev tools nor in fiddler. I'm using the latest version of the Skype SDk bootstrapper.
Both clients and server are in the same subnet.
Thanks in advance.
I encountered the same problem. Not sure how it happens, but the sdk has troubles to fetch or apply the media config.
You can use the this workaround:
Following line 18,892 in the debug version of the sdk, comment out both calls:
uninit();
throw error;
in the function init() of the section MediaConfig. Resulting in:
function init() {
pcMediaConfig = mediaPlugin.createComponent({
type: 'MediaPlatformConfig',
hide: true,
inproc: false
});
pcMediaConfig.event(onPluginComponentEvent);
pcMediaConfig.state.changed(function (state) {
log('pcMediaConfig.state = ' + state);
});
var p = pcMediaConfig.load().then(getMediaConfig).then(setMediaConfig).then(null, function (error) {
log('MediaConfig::init rejected');
//uninit();
//throw error;
});
return p;
}
Therefore you have to download the bootstrapper and the sdk to permanently apply the patch. To do this just fetch both in the debug version (bootstrapper version 1.2.5) and replace in function onConfig(config) line 48
}, config.corsScript && (scriptAttributes.crossOrigin = ""), loader.loadScript(getPackageUrl(config), null, handleError, scriptAttributes);
with
}, config.corsScript && (scriptAttributes.crossOrigin = ""), loader.loadScript("./scripts/SkypeSDK.js", null, handleError, scriptAttributes);
or your equivalent path
This is currently a limitation of the Skype Web SDK: it has a dependency on the mediaRelayAccessToken to proceed with audio/video calls. The dev team is aware of this issue and it may be fixed in a future release of Skype Web SDK.
The hacky way recommended above is basically to allow the SDK to continue the call upon missing mediaRelayAccessToken, so it may let you bypass the issue.
The media relay access token is returned by an edge server, so you may also try to deploy an edge server to work around this issue.

WCSessionDelegate: sessionDidBecomeInactive and sessionDidDeactivate have been marked unavailable, but are required

I just converted a Swift 2 app to Swift 3, using the convert function of Xcode 8.
My code has a class marked as WCSessionDelegate.
In Swift 2 it compiled without the methods sessionDidBecomeInactive and sessionDidDeactivate.
If I compile the Swift 3 version, the compiler complains that my class does not conform to protocol WCSessionDelegate, which is apparently correct.
It then offers to insert stubs for both functions:
public func sessionDidBecomeInactive(_ session: WCSession) { }
public func sessionDidDeactivate(_ session: WCSession) { }
After these stubs are inserted, these errors are reported:
Cannot override 'sessionDidBecomeInactive' which has been marked unavailable
Cannot override 'sessionDidDeactivate' which has been marked unavailable
How can I fix this problem?
Because the delegate methods sessionDidDeactivate and sessionDidBecomeInactive are marked as unavailable on watchOS you will have to make the compiler ignore those pieces of code in the shared class. You can do so using the following preprocessor macro:
#if os(iOS)
public func sessionDidBecomeInactive(_ session: WCSession) { }
public func sessionDidDeactivate(_ session: WCSession) {
session.activate()
}
#endif
Please also note I added the activate call in the sessionDidDeactivate call. This is to re-activate the session on the phone when the user has switched from one paired watch to second paired one. Calling it like this assumes that you have no other threads/part of your code that needs to be given time before the switch occurs. For more information on supporting the quick watch switching you should take a look at the Apple sample code

NSFileProtectionComplete doesn't encrypt the core data file

I am using Xcode 7.3 for iOS 9.3 to try and encrypt a Core Data file. I am trying to use NSPersistentStoreFileProtectionKey and set it to NSFileProtectionComplete to enable the encryption. It is not working for some reason and I can always see the .sqlite file generated by the app and browse through the content in sqlitebrowser or iexplorer. Here is my code :
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
// Create the coordinator and store
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
let dict: [NSObject : AnyObject] = [
NSPersistentStoreFileProtectionKey : NSFileProtectionComplete
]
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: dict)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
do {
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
try NSFileManager.defaultManager().setAttributes([NSFileProtectionKey : NSFileProtectionComplete], ofItemAtPath: url.path!)
} catch {
}
do {
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite-wal")
try NSFileManager.defaultManager().setAttributes([NSFileProtectionKey : NSFileProtectionComplete], ofItemAtPath: url.path!)
// try print(NSFileManager.defaultManager().attributesOfFileSystemForPath(String(url)))
} catch {
}
do {
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite-shm")
try NSFileManager.defaultManager().setAttributes([NSFileProtectionKey : NSFileProtectionComplete], ofItemAtPath: url.path!)
// try print(NSFileManager.defaultManager().attributesOfFileSystemForPath(String(url)))
} catch {
}
return coordinator
}()
I have also enabled Data Protection for my target in the "Capabilities". I have regenerated the provisioning profile from the Apple Developer portal and am using that with Enabled Data Protection.
I am also using the following code to check the file attributes of .sqlite , .sqlite-wal and .sqlite-shm files. NSFileProtectionKey is correctly set for all 3 of them.
func checkProtectionForLocalDb(atDir : String){
let fileManager = NSFileManager.defaultManager()
let enumerator: NSDirectoryEnumerator = fileManager.enumeratorAtPath(atDir)!
for path in enumerator {
let attr : NSDictionary = enumerator.fileAttributes!
print(attr)
}
}
I also tried disabling the Journal mode to prevent -wal and -shm files from being created. But I can still read the .sqlite file. Even though the attributes read NSFileProtectionComplete.
As described in the Apple Documentation at Apple Docs under "Protecting Data using On Disk Encryption", I tried to check whether the value of variable protectedDataAvailable changes as shown in the code below
public func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
NSThread.sleepForTimeInterval(10)
sleep(10)
let dataAvailable : Bool = UIApplication.sharedApplication().protectedDataAvailable
print("Protected Data Available : " + String(dataAvailable))
}
If I check the value without the delay it's set to true but after adding the delay it's set to false. This is kind of encouraging, however, right after, when I download the container, to show the content, it still has .sqlite file that still shows the content when opened in sqlitebrowser.
Ok, I finally understand this.
Using Xcode 7.3.1
Enabling File Protection
Enable File Protection using the Capabilities tab on your app target
If you do not want the default NSFileProtectionComplete, change this setting in the developer portal under your app id
Make sure Xcode has the new provisioning profile this creates.
For protecting files your app creates, that's it.
To protect Core Data, you need to add the NSPersistentStoreFileProtectionKey: NSFileProtectionComplete option to your persistent store.
Example:
var options: [NSObject : AnyObject] = [NSMigratePersistentStoresAutomaticallyOption: true,
NSPersistentStoreFileProtectionKey: NSFileProtectionComplete,
NSInferMappingModelAutomaticallyOption: true]
do {
try coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: options)
Testing File Protection
I am not able to test this using a non-jailbroken device connected to a computer. Every attempt to access the device this way requires that I "trust" the computer and I believe that trusted computers are always able to read the phone's data ("Trusted computers can sync with your iOS device, create backups, and access your device's photos, videos, contacts, and other content" - https://support.apple.com/en-us/HT202778). I think the other answers on SO referencing this technique are no longer valid with more recent versions of iOS. Indeed, I am always able to download the container using XCode and view the app's data using iPhone Explorer. So how to test...
1 - Create an archive and ensure that it is has the proper entitlements by running the following on the .app file from the command line:
codesign -d --entitlements :- <path_to_app_binary>
You should see a key/value pair that represents your Data Protection level. In this example, NSFileProtectionComplete:
<key>com.apple.developer.default-data-protection</key>
<string>NSFileProtectionComplete</string>
In addition, I used the following two techniques to satisfy myself that the data protection is indeed working. They both require code changes.
2 - Add some code to verify that the proper NSFileProtectionKey is being set on your files and/or core data store:
NSFileManager.defaultManager().attributesOfItemAtPath(dbPath.path!)
If I print this out on one of my files I get:
["NSFileCreationDate": 2016-10-14 02:06:39 +0000, "NSFileGroupOwnerAccountName": mobile, "NSFileType": NSFileTypeRegular, "NSFileSystemNumber": 16777218, "NSFileOwnerAccountName": mobile, "NSFileReferenceCount": 1, "NSFileModificationDate": 2016-10-14 02:06:39 +0000, "NSFileExtensionHidden": 0, "NSFileSize": 81920, "NSFileGroupOwnerAccountID": 501, "NSFileOwnerAccountID": 501, "NSFilePosixPermissions": 420, "NSFileProtectionKey": NSFileProtectionComplete, "NSFileSystemFileNumber": 270902]
Note the "NSFileProtectionKey": "NSFileProtectionComplete" pair.
3 - Modify the following code and hook it up to some button in your app.
#IBAction func settingButtonTouch(sender: AnyObject) {
updateTimer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self,
selector: #selector(TabbedOverviewViewController.runTest), userInfo: nil, repeats: true)
registerBackgroundTask()
}
var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
var updateTimer: NSTimer?
func registerBackgroundTask() {
backgroundTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler {
[unowned self] in
self.endBackgroundTask()
}
assert(backgroundTask != UIBackgroundTaskInvalid)
}
func endBackgroundTask() {
NSLog("Background task ended.")
UIApplication.sharedApplication().endBackgroundTask(backgroundTask)
backgroundTask = UIBackgroundTaskInvalid
}
func runTest() {
switch UIApplication.sharedApplication().applicationState {
case .Active:
NSLog("App is active.")
checkFiles()
case .Background:
NSLog("App is backgrounded.")
checkFiles()
case .Inactive:
break
}
}
func checkFiles() {
// attempt to access a protected resource, i.e. a core data store or file
}
When you tap the button this code begins executing the checkFiles method every .5 seconds. This should run indefinitely with the app in the foreground or background - until you lock your phone. At that point it should reliably fail after roughly 10 seconds - exactly as described in the description of NSFileProtectionComplete.
We need to understand how Data Protection works.
Actually, you don't even need to enable it. Starting with iOS7, the default protection level is “File Protection Complete until first user authentication.”
This means that the files are not accessible until the user unlocks the device for the first time. After that, the files remain accessible even when the device is locked and until it shuts down or reboots.
The other thing is that you're going to see the app's data on a trusted computer always - regardless of the Data Protection level setting.
However, the data can’t be accessed if somebody tries to read them from the flash drive directly. The purpose of Data Protection is to ensure that sensitive data can’t be extracted from a password-protected device’s storage.
After running this code, I could still access and read the contents written to protectedFileURL, even after locking the device.
do {
try data.write(to: protectedFileURL, options: .completeFileProtectionUnlessOpen)
} catch {
print(error)
}
But that's normal since I ran iExplorer on a trusted computer.
And for the same reason, it's fine if you see your sqlite file.
The situation is different if your device gets lost or stolen. A hacker won't be able to read the sqlite file since it's encrypted. Well, unless he guesses your passcode somehow.
Swift 5.0 & Xcode 11:
Enable "Data Protection" in "Capabilities".
Use the following code to protect a file or folder at a specific path:
// Protects a file or folder + excludes it from backup.
// - parameter path: Path component of the file.
// - parameter fileProtectionType: `FileProtectionType`.
// - returns: True, when protected successful.
static func protectFileOrFolderAtPath(_ path: String, fileProtectionType: FileProtectionType) -> Bool {
guard FileManager.default.fileExists(atPath: path) else { return false }
let fileProtectionAttrs = [FileAttributeKey.protectionKey: fileProtectionType]
do {
try FileManager.default.setAttributes(fileProtectionAttrs, ofItemAtPath: path)
return true
} catch {
assertionFailure("Failed protecting path with error: \(error).")
return false
}
}
(Optional) Use the following code to check whether the file or folder at the specific path is protected (note: This only works on physical devices):
/// Returns true, when the file at the provided path is protected.
/// - parameter path: Path of the file to check.
/// - note: Returns true, for simulators. Simulators do not have hardware file encryption. This feature is only available for real devices.
static func isFileProtectedAtPath(_ path: String) -> Bool {
guard !Environment.isSimulator else { return true } // file protection does not work on simulator!
do {
let attributes = try FileManager.default.attributesOfItem(atPath: path)
if attributes.contains(where: { $0.key == .protectionKey }) {
return true
} else {
return false
}
} catch {
assertionFailure(String(describing: error))
return false
}
}
Rather than encrypt a file at the local level I set NSFileProtectionComplete for the app as a whole.
Create the file 'entitlements.plist' in your apps root folder with the following content.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>DataProtectionClass</key>
<string>NSFileProtectionComplete</string>
</dict>
</plist>
Then if you haven't already done so already (this could be the problem with your file level encryption) enable Data Protection in your apps capabilities.

meteor-testing tutorial fails

I started the meteor-testing tutorial, but the 2nd automatic generated test fails with:
TypeError: Cannot call method 'url' of undefined
So it seems that the client variable is not defined. Did anybody experience similar issues? (btw is there a way to debug this)
i'm using ubuntu 14.04 with
Meteor 1.2.0.2
node v4.0.0
xolvio:cucumber 0.19.4_1 CucumberJS for Velocity
Update:
Generated test code intests/cucumber/features/step_definitions/sample_steps.js:
// You can include npm dependencies for support files in tests/cucumber/package.json
var _ = require('underscore');
module.exports = function () {
// You can use normal require here, cucumber is NOT run in a Meteor context (by design)
var url = require('url');
// 1st TEST OK
this.Given(/^I am a new user$/, function () {
server.call('reset'); // server is a connection to the mirror
});
// 2nd TEST FAIL
this.When(/^I navigate to "([^"]*)"$/, function (relativePath) {
// process.env.ROOT_URL always points to the mirror
client.url(url.resolve(process.env.ROOT_URL, relativePath));
});
...
};
I was said to file an issue in the chimp repository, where I was pointed to the solution:
// 2nd TEST FAIL
this.When(/^I navigate to "([^"]*)"$/, function (relativePath) {
// REPLACE client with browser
browser.url(url.resolve(process.env.ROOT_URL, relativePath));
});
This is a short fix, but I'm not sure whether you should later rather use client (seems to be wrapper for different environments).
**Update: ** meanwhile this was fixed, no adaption necessary anymore

Resources