繁体   English   中英

如何实现 AutoFill Credential Provider Extensions - iOS 11、swift4

[英]How to implement AutoFill Credential Provider Extensions - iOS 11, swift4

很长一段时间以来,我一直在 iOS 自动填充凭证扩展中工作。 查了这么多iOS的文章和视频。 但我无法在快速输入栏上显示凭据,重置内容已成功集成。 任何人都可以给我快速帮助吗?

使用此视频和从苹果共享的 url: https://developer.apple.com/videos/play/wwdc2018/721 https://developer.apple.com/documentation/authenticationservices
我正在使用以下代码将凭据保存到特定域的钥匙串。

    let keychain = Keychain(server: "instagram.com", protocolType: .https, authenticationType: .htmlForm)
    keychain["emailAddress"] = "Password"

并使用此代码保存域:

func savedomain(domain: String, account: String, password: String, completion: ((Bool, SharedWebCredentialsManagerError?) -> Void)? = nil) {
    SecAddSharedWebCredential(domain as CFString, account as CFString, password as CFString?) { error in
        guard let error = error else {
            completion?(true, nil)
            return
        }
        let errorDescription = CFErrorCopyDescription(error) as String
        let saveFailedError = SharedWebCredentialsManagerError.saveFailed(errorDescription)
        completion?(false, saveFailedError)
    }
}

我已经创建了自动填充扩展程序并获取了已保存的凭据,但无法在 safari 的快速输入栏上显示凭据以供 instagram.com

我已经为所有社交网站实现了自动填充扩展,共享我的源代码以使用域保存 emailID-Password。

class func save(key: String, data: Data) -> OSStatus {
    let query = [
        kSecClass as String       : kSecClassGenericPassword as String,
        kSecAttrAccount as String : key,
        kSecValueData as String   : data ] as [String : Any]

    SecItemDelete(query as CFDictionary)

    return SecItemAdd(query as CFDictionary, nil)
}

上面我已经写在我的自定义KeyChainManager类“保存”功能,此外,我添加以下代码KeyChainManager类,如下所示。

extension Data {

init<T>(from value: T) {
    var value = value
    self.init(buffer: UnsafeBufferPointer(start: &value, count: 1))
}

func to<T>(type: T.Type) -> T {
    return self.withUnsafeBytes { $0.load(as: T.self) }
}

}

我通过调用我们的KeyChainManager 类来从 VC 保存我的数据,如下所示:

let email = (txtEmail?.text ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
        let password = (txtPassword?.text ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
        let domain = (txtDomain?.text ?? "").lowercased().trimmingCharacters(in: .whitespacesAndNewlines)
        
        let user = User(email: email, password: password, key: self.key, domain: domain, identifier: self.keyIdentifier)
        let data = (try? JSONEncoder().encode(user)) ?? Data()
        let _ = KeyChain.save(key: "\(self.keyIdentifier)", data: data)

这一切都是为了保存我们的凭据,现在重点是如何在我们的扩展的CredentialProviderViewController.swift 中列出所有保存的凭据

为此,我在KeyChainManager 类中添加了以下方法:

class func load(key: String) -> Data? {
    
    let query = [
        kSecClass as String       : kSecClassGenericPassword,
        kSecAttrAccount as String : key,
        kSecReturnData as String  : kCFBooleanTrue!,
        kSecMatchLimit as String  : kSecMatchLimitOne ] as [String : Any]

    var dataTypeRef: AnyObject? = nil

    let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)

    if status == noErr {
        return dataTypeRef as! Data?
    } else {
        return nil
    }
}

并从扩展的CredentialProviderViewController.swift调用此函数,如下所示:

users.removeAll()
    for i in 0..<1000000 {
        if let encodedData = KeyChain.load(key: "\(i)")  {
            let user = try! JSONDecoder().decode(User.self, from: encodedData)
            if user.key == key && ((serviceIdentifier.contains(user.domain ?? "")) ) {
                users.append(user)
            }
        }else{
            break
        }
    }

我希望这个内容能帮助你,因为我花了很多天时间只创建一个演示 :) :) 在下面评论,如果它对你有帮助 :) :)

谢谢,安贾利。

为了在快速栏上显示凭据,您必须制作ASPasswordCredentialIdentity对象并将其保存在ASCredentialIdentityStore中,这是链接。 https://developer.apple.com/documentation/authenticationservices/ascredentialidentitystore希望获得帮助。

您需要填充 ASCredentialIdentityStore 以便快速输入栏工作。 参见ASCredentialProviderViewController的描述:

(可选)将 ASPasswordCredentialIdentity 实例添加到共享的 ASCredentialIdentityStore 以直接在 QuickType 栏中提供身份。

这也在您参考的 WWDC 演示文稿中进行了描述。

我如何实现 ASCredentialIdentityStore 的填充:

        var firstItem = ASPasswordCredentialIdentity(serviceIdentifier: ASCredentialServiceIdentifier(identifier: "https://online.somebank.com/auth/login", type: .URL), user: "login@bank.com", recordIdentifier: nil)
    ASCredentialIdentityStore.shared.replaceCredentialIdentities(with: [firstItem]) { result, error in
        if result {
            print("saved")
        }
    }

就我而言,一切都很完美。 因此,我从远程获取所有密码,然后使用可用密码填充 ASCredentialIdentityStore。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM