Posts

Post marked as solved
7 Replies
7.8k Views
HiUsing the newer methods in the SDK for iOS 10, I can generate private and public keys, with the private key residing in the Keychain. The public key is exported.Here's my code thus far: func createKeyPair(_ keyName: String, authenticationRequired: SecAccessControlCreateFlags? = nil, completion: (_ success: Bool, _ publicKeyData: Data?) -> Void) { guard !keyName.isEmpty else { NSLog("\tNo keyname provided.") return completion(false, nil) } var error: Unmanaged<CFError>? // Private key parameters var privateKeyParams: [String: Any] = [ kSecAttrIsPermanent as String: true, kSecAttrApplicationTag as String: keyName ] // If we are using a biometric sensor to access the key, we need to create an SecAccessControl instance. if authenticationRequired != nil { guard let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, authenticationRequired!, &error) else { NSLog("\tError: %@", error!.takeRetainedValue().localizedDescription) completion(false, nil) return } privateKeyParams[kSecAttrAccessControl as String] = accessControl } / let parameters: [String: Any] = [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeySizeInBits as String: 2048, kSecPrivateKeyAttrs as String: privateKeyParams ] // Global parameters for our key generation guard let privateKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else { NSLog("\tError generating keypair. %@", "\(error!.takeRetainedValue().localizedDescription)") return completion(false, nil) } // Generate the keys. guard let publicKey = SecKeyCopyPublicKey(privateKey) else { NSLog("\tError obtaining public key.") return completion(false, nil) } // Get the public key. guard let privateKeyData = SecKeyCopyExternalRepresentation(privateKey, nil) else { NSLog("\tError obtaining export of private key.") return completion(false, nil) } print("\nPrivate key: \(String(describing: exportPublicKey(privateKeyData as Data)))") // Extract the public key for export. guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, nil) else { NSLog("\tError obtaining export of public key.") return completion(false, nil) } completion(true, publicKeyData as Data) } public func exportPublicKey(_ rawPublicKeyBytes: Data, base64EncodingOptions: Data.Base64EncodingOptions = []) -> String? { return rawPublicKeyBytes.base64EncodedString(options: base64EncodingOptions) } // Call the function like so. _ = createKeyPair(keyName) { (status, data) in if status { print("exporting public key: \(String(describing: exportPublicKey(data!)))") } }If I've understood the documentation, SecKeyCopyExternalRepresentation says that the method returns data in the PCKS #1 format for an RSA key. From the various forums, I'm lead to beleive that simply base64 encoding to a string the output of SecKeyCopyExternalRepresentation is all that is required to export the public key in PEM format (without BEGIN RSA PUBLIC KEY and END RSA PUBLIC KEY)When the public key is used to validate some signed data in a Java app, the public key fails to load with invalid key errors... Anyone provide some guidance on this?Thanks
Posted
by craigaps.
Last updated
.
Post not yet marked as solved
4 Replies
490 Views
HiI have a protocol as follows:protocol Profile: Codable, Identifiable { var id: String { get } var name: String { get } }With 2 implemenations as follows:struct Customer: Profile { let id: String let name: String let country: String } struct Contractor: Profile { let id: String let name: String let trade: String let companyName: String }I have a struct that encapsulates either the customer or contractor, but I don't what type of profile it will be at initialization time. So something like:final class UserData: ObservableObject, Codable { var account: Profile? }But the code doesn't compile with the error:Protocol 'Profile' can only be used as a generic constraint because it has Self or associated type requirements.How I'd like to use UserData is by:var user = UserData() user.account = getAccount() func getAccount() -> Profile? { // decode JSON from file, returning a Custoemr or Contractor return Customer(id: "123", name: "Bill", country: "USA") }I'm struggling to assign account to an optional protocol. Appreciate any help and guidence.Thanks
Posted
by craigaps.
Last updated
.
Post marked as solved
3 Replies
528 Views
HiI'm trying to display a sheet when the app first launches, similiar to when you upraded iOS to 13 and tapped say reminders.But I'm struggling to get with working with SwiftUI, here is a snippet of the code. It essentially crashes the app.import SwiftUI struct ContentView: View { @State private var showingSheet = false var body: some View { return self.sheet(isPresented: $showingSheet) { RegisterHome() } } } struct RegisterHome: View { var body: some View { NavigationView { Text("Register") .navigationBarTitle("Register") } } }Any thoughts would be very much appreciated.Thanks, Craig
Posted
by craigaps.
Last updated
.
Post marked as solved
6 Replies
539 Views
HiI'm using enum and wanted to write an extension to expose additional case values. Just confirming that this is not possible in Swift 5.1. I was thinking something like:import CryptoKit extension CryptoKitError { enum `Self` : Error { /// The data used to deserialized a key with `SecKeyCreateWithData` was incorrect. case incorrectKeyData /// The generation of the failed. case keyFailure } }The closest usage I example is:throw CryptoKitError.Self.keyFailureWhat I'd really want is:throw CryptoKitError.keyFailureThanks
Posted
by craigaps.
Last updated
.
Post marked as solved
1 Replies
6.0k Views
I have a framework project built in Xcode 10, Swift 5 and targeting iOS 11. I've opened the project up in Xcode 11 BETA 4 and executed a build via the command line. I set the Xcode Location setting to Command Line Tools: Xcode 11.0 (11M374r). Here is my xcodebuild arguments:xcodebuild -configuration Release -target MySDKKit -sdk iphoneos -scheme "My SDK Build" -derivedDataPath ./build clean buildIn the project itself, I have the following:User-Defined BITCODE_GENERATION_MODE Debug marker Release bitcodeThe rest of the project build settings are pretty much out of the box. The Valid Architectures arm64 arm64e armv7 armv7sSo here is the error:ld: symbol(s) not found for architecture arm64clang: error: linker command failed with exit code 1 (use -v to see invocation)** BUILD FAILED **The following build commands failed: Ld /Users/craig/Documents/Xcode/sdk-ios/MySDKKit/build/Build/Products/Release-iphoneos/MySDKKit.framework/MySDKKit normal arm64If I remove the Bitcode setting the project builds fine, but I can;t make an archive in an app project. If I enable Bitcode and target iOS 13, the build will also build without issue.Any ideas?Many thanksCraig
Posted
by craigaps.
Last updated
.
Post marked as solved
2 Replies
957 Views
HiI'm trying to figure out why the compiler is throwing this error at me:Cannot convert value of type '((Bool) -> Void) -> ()' to expected argument type '(Bool) -> Void'Here is my struct and initialization:struct Item { var title = String() var didFail = Bool() var execute: ((Bool) -> Void) } func doSomething(completion: @escaping (Bool) -> Void) { completion(true) } var item = Item(title: "Fred", didFail: false, execute: doSomething) item.execute { result in print("Result: \(result)") }Any ideas as to why this error might be happening. I refactored the execute to take an argument and no closure and it worked fine; but I'd really like to use the callback approach.Many thanksCraig
Posted
by craigaps.
Last updated
.
Post not yet marked as solved
3 Replies
6.0k Views
HiI have a Universal Swift Framework built in Xcode 10 Swift 4.2 and I want to display some messages depending on Active Compilation Condition flags that are provided by the app. For example a struct in the Framework contains the following:public struct Person { public let name: String public let age: Int public init(from decoder: Decoder) throws { #if LOG NSLog("Log A") #else NSLog("No Log") #endif ... } }In the app that has the Framework embeded, I would set LOG in the Active Compilation Condition for Debug (Any Architecture). So when the app is running in either simulator or on the actual device and the person struct is initialized, I would see "Log A" appear in the Console or Debug area (in Xcode).I haven't been able to get this to work, "No Log" appears. Have I misunderstood the prupose of using Active Compilation Conditon 😕Appreciate any help.Thanks
Posted
by craigaps.
Last updated
.
Post marked as solved
3 Replies
3.5k Views
HiI have 2 projects, 1 is a framework, the other being an app that uses the fraemwork. Both build settings specify the following:iOS Deployment target = iOS 10.0Swift Language Version = Swift 4.2Architectures = Standard architecturesSupported Platforms = iOSValid Architectures = arm64 armv7 armv7sEnable Bitcode = YesThe framework uses a Run Script in the Build Phases to create a universal build of the framework. In the app, the Run Script Build Phrase copies a "thinned" version of the framework depending on the target i.e device or simulator.Both project build successfully and I can generate an archive from the app project. However when I attempt to generate the distribution which involves compiling for bitcode, the export IPA fails to to create with the following error:error: Failed to compile bundle: /var/folders/qk/pl28fvfj6fqfwmvhg98n9xy80000gn/T/IBMVerifyKitrIN5Ft/MyApp.armv7.xar\n \n\nStderr:\n\n>\n /Applications/Xcode-beta.app/Contents/Developer/usr/bin/ipatool:248:in `run'\n /Applications/Xcode-beta.app/Contents/Developer/usr/bin/ipatool:2399:in `block in CompileOrStripBitcodeInBundle'\n /Applications/Xcode-beta.app/Contents/Developer/usr/bin/ipatool:2338:in `each'\n /Applications/Xcode-beta.app/Contents/Developer/usr/bin/ipatool:2338:in `CompileOrStripBitcodeInBundle'\n /Applications/Xcode-beta.app/Contents/Developer/usr/bin/ipatool:2543:in `ProcessIPA'\n /Applications/Xcode-beta.app/Contents/Developer/usr/bin/ipatool:3346:in `<main>'"; info = { }; level = ERROR; type = exception; } ); thinnableAssetCatalogs = ( "/var/folders/qk/pl28fvfj6fqfwmvhg98n9xy80000gn/T/XcodeDistPipeline.zof/Root/Payload/MyApp.app/Assets.car" );} -= Output =- Undefined symbols for architecture armv7: "___llvm_profile_runtime", referenced from: __hidden#436_ in 01.o __hidden#436_ in 02.o __hidden#436_ in 03.o __hidden#436_ in 05.o __hidden#436_ in 06.o __hidden#436_ in 07.o __hidden#436_ in 08.o ... ld: symbol(s) not found for architecture armv7 Exited with 1 error: Failed to compile bundle: /var/folders/qk/pl28fvfj6fqfwmvhg98n9xy80000gn/T/MyFramworkKit2Q7zfl/MyFrameworkKit.armv7.xarAny ideas? Impossible for me to proceed with uploading to Test Flight while this error occurs...Thanks
Posted
by craigaps.
Last updated
.
Post not yet marked as solved
1 Replies
2.7k Views
HiUsers are prmpted for the Push Notification permission when they first download and launch the app. If the user taps "Don't Allow", the user has no way to turn on notifcations unless the app is removed, downloaded and launched again.I would have thought even if the toggle was disabled Notifications would appear in the Settings > My App > Notifications.Anyone has some ideas as to what the best practice is to provide the user the ability to enable notifications at a later stage if initially they denied the permission?ThanksCraig
Posted
by craigaps.
Last updated
.
Post not yet marked as solved
4 Replies
1.6k Views
HiThe sample code below I lifted from another another post, let's go with this example to describe what I'm trying to do. https://forums.developer.apple.com/message/86598#Let's say fetchOp fails due to an authentication error. I want to kick off another operation to re-authenticate, then retry the fetchOp. What's would be the best approach for achieving this?class FetchOperation: NSOperation { var url: NSURL? var data: NSData? var error: NSError? convenience init(url: NSURL) { self.init() self.url = url } // I've omitted the intricacies of implementing an async // network operation because that’s too complex a topic to // cover here. The only thing to watch out for is that, for // adapter operations to work in a fully composible fashion, // the start of the async code must check self.error and fail // immediately if it’s set. } class ParseOperation: NSOperation { var data: NSData? var error: NSError? convenience init(data: NSData) { self.init() self.data = data } override func main() { if self.error == nil { if let data = self.data { self.parseData(data) } else { // We have no data to parse; this shouldn't happen. fatalError() } } } func parseData(data: NSData) { // ... parse the data ... } } let fetchOp = FetchOperation(url: url) let parseOp = ParseOperation() let adapterOp = NSBlockOperation(block: { parseOp.data = fetchOp.data parseOp.error = fetchOp.error }) adapterOp.addDependency(fetchOp) parseOp.addDependency(adapterOp) networkQueue.addOperation(fetchOp) computeQueue.addOperation(adapterOp) computeQueue.addOperation(parseOp) Many thanks
Posted
by craigaps.
Last updated
.
Post marked as solved
1 Replies
653 Views
HiI'm trying to figure out the following gives me an error.protocol SomeProtocol { var name: String { get set } } class SomeName : SomeProtocol { public var name: String init() { self.name = "" } init(name: String) { self.name = name } } class SomeContext { private init() { } open static let shared = SomeContext() public func someMethod(with value: inout T, age: [Int]) { print("before: \(value.name)") value.name = "foo" print("after: \(value.name)") print("age: \(age)") } } func createSomeName() { var value = SomeName(name: "Fred") testInout(value: &value) print(value.name) } func testInout(value: inout SomeProtocol) { SomeContext.shared.someMethod(with: &value, age: [1,2,3]) } createSomeName()On line 47, I get this error:error: cannot pass immutable value as inout argument: implicit conversion from 'SomeName' to 'SomeProtocol' requires a temporary testInout(value: &value)On line 53, I get this error:error: in argument type 'inout SomeProtocol', 'SomeProtocol' does not conform to expected type 'SomeProtocol' SomeContext.shared.someMethod(with: &value, age: [1,2,3])Basically I need to be able to pass class/or struct to a method, which passes it to another method which can modify the value i.e name. I tried using a struct but ended up with the same errors.If I replace line 47 with line 53, it seems to work fine with either a struct or classAny ideas how to work around this problem?Thanks
Posted
by craigaps.
Last updated
.
Post marked as solved
2 Replies
2.1k Views
HiI'm trying to use SecKeyCreateSignature to sign a string but seem to have missed something. Here is my code snippet:public static func sign(using name: String, value: String, base64EncodingOptions: Data.Base64EncodingOptions = []) -> String? { // Get private key by name using SecItemCopyMatching guard let privateKey: SecKey = getPrivateKey(name) else { return nil } let data = value.data(using: .utf8)! var error: Unmanaged<CFError>? guard let signedData = SecKeyCreateSignature(privateKey, .rsaSignatureDigestPKCS1v15SHA512, data as CFData, &error) as Data? else { return nil } return signedData.base64EncodedString(options: base64EncodingOptions) }And to call the method:let result = sign("MyKey", "hello world") print(result)Using the public key generated on iOS and exported to Java, the validation fails. I'm think it might be something to do with value.data(using: .utf8) but I'm not sure. Using the older style SecKeyRawSign you would hash the "hello world" value before invoking SecKeyRawSignAny ideas or a simple example would be great 🙂
Posted
by craigaps.
Last updated
.
Post not yet marked as solved
4 Replies
1.4k Views
HiSimilar question to https://forums.developer.apple.com/thread/79327?q=protocol%20codable I'm not sure if it's a bug or not.Here is my scenario, best described in code...import Foundation public protocol MyProtocol : Codable { var name: String { get set } } public struct MyStruct : MyProtocol { public var name: String public var id: Int private enum CodingKeys : String, CodingKey { case id case name } init(id: Int, name: String) { self.id = id self.name = name } /// Decode public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.id = try container.decode(Int.self, forKey: .id) self.name = try container.decode(String.self, forKey: .name) } /// Encode public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(id, forKey: .id) try container.encode(name, forKey: .name) } } public class MyClass { public static func doSomething(completion: @escaping (MyProtocol) -> Void) { let myStruct = MyStruct(id: 2, name: "Fred") completion(myStruct) } } MyClass.doSomething() { (result) in let value = try? JSONEncoder().encode(result) guard value == nil else { return } let json = String(data: value!, encoding: .utf8) print(json) }The error I get in playgrounds is:Playground execution failed:error: Samplecode.playground:43:36: error: cannot invoke 'encode' with an argument list of type '((MyProtocol))' let value = try? JSONEncoder().encode(result) ^Samplecode.playground:43:36: note: expected an argument list of type '(T)' let value = try? JSONEncoder().encode(result)If MyStruct doesn't implement init(from decoder: Decoder) or func encode(to encoder: Encoder) the compiler throws an error. So once these codable func's are implemented what is the compiler complaining about??I've also made init(from decoder: Decoder) or func encode(to encoder: Encoder) as an extension to MyStruct, same errorAny ideas?
Posted
by craigaps.
Last updated
.
Post not yet marked as solved
2 Replies
726 Views
HiI'm unit testing some functions with completion handlers but I'm unable to get the callbacks to fire 😕 Here is the code being tested:public class MyClass1 { static func updateName(with myStruct: inout MyStruct, completion: @escaping (Error?) -> Void) { var newName: String? var updateError: Error? MyClass2.createNewName() { (name, error) in newName = name updateError = error } / if let newName = newName { myStruct.name = newName } completion(updateError) } } public class MyClass2 { static func createNewName(completion: @escaping (String?, Error?) -> Void) { guard let url = URL(string: "http://jsonplaceholder.typicode.com/users/1") else { return completion(nil, nil) } let task = URLSession.shared.dataTask(with: url) { (data, response, error) in if error != nil { completion(nil, error) } if let data = data { let result = String(data: data, encoding: .utf8) completion(result, error) } } task.resume() } } public struct MyStruct { private var _name: String init(name: String) { self._name = name } public var name: String { get { return self._name } set { self._name = newValue } } }When I execute MyClass2.createNewName directly, the completion block executes and the function suceeds fine.However, when I call MyClass1.updateName which calls into MyClass2.createNewName the completion block in MyClass2.createNewName doesn't get executed and the myStruct.name = newName is never hit.Here's the Playground test to demonstrate:import Foundation import XCPlayground XCPSetExecutionShouldContinueIndefinitely() var pet = MyStruct(name: "dog") print("--Using Class1--") print("Old name: \(pet.name)") MyClass1.updateName(with: &pet) { (error) in print("error: \(String(describing: error))") } print("New name: \(pet.name)") print("\n") var person = MyStruct(name: "Jimmy") print("--Using Class2--") print("Old name: \(person.name)") MyClass2.createNewName() { (newName, error) in guard error == nil else { print("error: \(String(describing: error))") return } person.name = newName! print("New name: \(person.name)") }Any suggestions to resolve this? If I add myStruct.name = newName withing the completion block, I end up with this error:error: escaping closures can only capture inout parameters explicitly by valueThanks
Posted
by craigaps.
Last updated
.