Failed dynamic config update - swift

I'm trying to "send" an image to snapchat using the Snapchat Creative Kit SDK.
Here is the code I'm using:
import UIKit
import SCSDKCreativeKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func addToSnapBtn(_ sender: UIButton) {
let urltest = URL(string: "http://via.placeholder.com/750x1334");
if let urltest = urltest as? URL {
let picture = SCSDKSnapPhoto(imageUrl: urltest.absoluteURL);
let snapPicture = SCSDKPhotoSnapContent(snapPhoto: picture);
snapPicture.caption = "Test image";
snapPicture.attachmentUrl = "https://google.com/";
let api = SCSDKSnapAPI();
api.startSending(snapPicture) { (error) in
if let error = error {
print(error);
} else {
print("YES");
}
}
}
}
When the user clicks on the button that is linked to the "addToSnapBtn" method I get the following error:
2019-06-14 00:38:14.454846+0200 prosnap[1540:84256] [SnapKit] path=/v1/config trace_id=917679DA29A144CEB5AD8E4C9446FB45
2019-06-14 00:38:14.808965+0200 prosnap[1540:84256] [SnapKit] Dynamic config update status: failure
I've looked everywhere. Documentation, google, stackoverflow, you name it.
I'm relatively new to iOS app development and I have no experience with snapkit.
Can somebody point me in the right direction?
Thanks in advance.

Don't define let api = SCSDKSnapAPI() in function. Define it in UIViewController. Because when you define let api in function it will deinits before completion runs. I tried and it works.

Related

practicing Core Data in Swift save method creates new entry everytime

I've been trying to figure out how Core Data works with using Swift. I don't think I'm grasping the proper concept of the whole thing. I get that I need to be interacting with Context to store data to PersistentContainer, but it seems everytime I press on save button, the data is stored as brand new. I want it to be able to update the existing row. Below is my code. Any help will be greatly appreciated. Thank you.
import UIKit
import CoreData
class ViewController: UIViewController {
var editNotes: Note?
let dataFilePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func saveButton(_ sender: UIButton) {
print (dataFilePath)
print (sender.tag)
var new: Note?
if let note = editNotes {
new = note
} else {
new = Note(context: context)
}
new?.body = textView.text
new?.date = NSDate() as Date
do {
ad.saveContext()
self.dismiss(animated: true, completion: nil)
} catch {
print(“cannot save”)
}
}
}

Implement AutoFill Credential Provider Extension in iOS14

I'm trying to implement the AutoFill Credential Provider Extension, however I'm having some problems following the video of the WWDC where they presented this feature.
Is there someone that has already done it that could help me?
Right now, I added the AutoFill Credential Provider capability as well as the AutoFill Credential Provider extension, which right now looks like this:
import AuthenticationServices
class CredentialProviderViewController: ASCredentialProviderViewController {
override func prepareCredentialList(for serviceIdentifiers: [ASCredentialServiceIdentifier]) {
}
override func provideCredentialWithoutUserInteraction(for credentialIdentity: ASPasswordCredentialIdentity) {
let databaseIsUnlocked = true
if (databaseIsUnlocked) {
let passwordCredential = ASPasswordCredential(user: "j_appleseed", password: "apple1234")
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential, completionHandler: nil)
} else {
self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code:ASExtensionError.userInteractionRequired.rawValue))
}
}
override func prepareInterfaceToProvideCredential(for credentialIdentity: ASPasswordCredentialIdentity) {
}
#IBAction func cancel(_ sender: AnyObject?) {
self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.userCanceled.rawValue))
}
#IBAction func passwordSelected(_ sender: AnyObject?) {
let passwordCredential = ASPasswordCredential(user: "j_appleseed", password: "apple1234")
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential, completionHandler: nil)
}
}
All of this was pre-written, but on the line
} else {
self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code:ASExtensionError.userInteractionRequired.rawValue))
}
I get the yellow warning "Will never be executed". Can someone help me understand how this extension works? Or is there a guide that I can follow? I can't find any nor on this website nor elsewhere on the internet.
There's not much in the way of documentation or sample code, and no tutorials that I can find. Essentially there is the video you already linked to, and the documentation for the ASCredentialProviderViewController class, which is here:
https://developer.apple.com/documentation/authenticationservices/ascredentialproviderviewcontroller?language=objc
But in your code, it should be quite clear why the line you quoted will never be executed. See my comments below:
let databaseIsUnlocked = true
if (databaseIsUnlocked) //this is always true, because you've just set it to be true
{
let passwordCredential = ASPasswordCredential(user: "j_appleseed", password: "apple1234")
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential, completionHandler: nil)
} else { //so there is no "else"
self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code:ASExtensionError.userInteractionRequired.rawValue))
}
Presumably Apple thought people might want to replace "databaseIsUnlocked = true" with a check to see if their database is unlocked. If that doesn't apply to you, you can ignore that bit.

Use of unresolved identifier 'FUIEmailAuth'FUIEmailAuth

I'm making a login screen using firebase auth UI and swift.
When I run the app, currently it only shows a welcome screen like this welcome screen.
But I want to display the page the firebase prebuilt UI with a text field that a user can type their email address, something like this. login-with email
Here is my current code.
import UIKit
import FirebaseUI
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
//MARK: - sign in / sign up
#IBAction func playPressed(_ sender: UIButton) {
let authUI = FUIAuth.defaultAuthUI()
guard authUI != nil else {
return
}
authUI?.delegate = self
authUI?.providers = [FUIEmailAuth()]
let authViewController = authUI!.authViewController()
present(authViewController, animated: true, completion: nil)
}
}
extension ViewController: FUIAuthDelegate{
func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) {
if error != nil {
return
}
performSegue(withIdentifier: K.loginSegue, sender: self)
}
}
and I get error on the code written as "authUI?.providers = [FUIEmailAuth()]". The error message is
Use of unresolved identifier 'FUIEmailAuth'FUIEmailAuth
I saw some other people run into the same problem, and I tried pod update, but I still get the error message.
Also, on the firebase document, they use 'FUIEmailAuth' in their sample code, so I wonder why I'm getting that error and how to fix it.
I just add pod 'FirebaseUI/Email' in my pod file and it solved the problem.

Basic Sinch Sample in Swift - but no Sound

first of all thank you for reading my lines.
For an idea I'm currently trying to dive into the Swift world (I only have very basic programming knowledge - no Objective C knowledge
).
I tried to set up the following lines to create a very basic app-to-app sample in Sinch. After my code I let you know what the issues are.
import UIKit
import Sinch
var appKey = "APP_KEY_FROM_MY_ACCOUNT"
var hostname = "clientapi.sinch.com"
var secret = "SECRET_FROM_MY_ACCOUNT"
class CViewController: UIViewController, SINCallClientDelegate, SINCallDelegate, SINClientDelegate {
var client: SINClient?
var call: SINCall?
var audio: SINAudioController?
//Text field in the main storyboard
#IBOutlet weak var userNameSepp: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.initSinchClient()
}
//initialize and start the client as a fixed "userA"
func initSinchClient() {
client = Sinch.client(withApplicationKey: appKey, applicationSecret: secret, environmentHost: hostname, userId: "userB")
client?.call().delegate = self
client?.delegate = self
client?.startListeningOnActiveConnection()
client?.setSupportCalling(true)
client?.start()
}
//Did the Client start?
func clientDidStart(_ client: SINClient!) {
print("Hello")
}
//Did the Client fail?
func clientDidFail(_ client: SINClient!, error: Error!) {
print("Good Bye")
}
//Call Button in the main.storyboard ... if call==nil do the call ... else hangup and set call to nil
//the background color changes are my "debugging" :D
#IBAction func callSepp(_ sender: Any) {
if call == nil{
call = client?.call()?.callUser(withId: userNameSepp.text)
//for testing I change to callPhoneNumber("+46000000000").
// the phone call progresses (but I hear nothing),
// the phonecall gets established (but I hear nothing)
// and the phonecall gets ended (but of course I hear nothing)
self.view.backgroundColor = UIColor.red
call?.delegate = self
audio = client?.audioController()
}
else{
call?.hangup()
self.view.backgroundColor = UIColor.blue
call = nil
}
}
func callDidProgress(_ call: SINCall?) {
self.view.backgroundColor = UIColor.green
client?.audioController().startPlayingSoundFile("/LONG_PATH/ringback.wav", loop: true)
print("Call in Progress")
}
//I know that this works but I don't hear anything
func callDidEstablish(_ call: SINCall!) {
client?.audioController().stopPlayingSoundFile()
print("Call did Establish")
}
func callDidEnd(_ call: SINCall!) {
print("Call did end")
}
// this works fine
#IBAction func hangUpSepp(_ sender: Any) {
call?.hangup()
self.view.backgroundColor = UIColor.red
call = nil
}
// i work in a "sub view controller" - so i navigate here back to the main view controller
#IBAction func goBackMain(_ sender: Any) {
call?.hangup()
dismiss(animated: true, completion: nil)
client?.stopListeningOnActiveConnection()
client?.terminateGracefully()
client = nil
}
}
So I can call my private phone number or if I change to callUser I can call another app but I don't hear anything. What do I miss? It must have to do with the SINAudioController and the client's method audioController() but I don't know what I'm doing wrong. Thank you for your help.

Unable to inject JS into WKWebView in Swift/Cocoa/NextStep / Push user selection on web page in WKWebView to Swift / Cocoa

I'm working with an MacOS app which needs to use the WKUserScript capability to send a message from the webpage back to the MacOS app. I'm working with the article https://medium.com/capital-one-tech/javascript-manipulation-on-ios-using-webkit-2b1115e7e405 which shows this working in iOS and works just fine.
However I've been struggling for several weeks to try to get it to work in my MacOS. Here is my example of his code which complies fine and runs but does not successfully print the message found in the handler userContentController()
import Cocoa
import WebKit
class ViewController: NSViewController, WKNavigationDelegate {
#IBOutlet weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let userContentController = WKUserContentController()
// Add script message handlers that, when run, will make the function
// window.webkit.messageHandlers.test.postMessage() available in all frames.
userContentController.add(self, name: "test")
// Inject JavaScript into the webpage. You can specify when your script will be injected and for
// which frames–all frames or the main frame only.
let scriptSource = "window.webkit.messageHandlers.test.postMessage(`Hello, world!`);"
let userScript = WKUserScript(source: scriptSource, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
userContentController.addUserScript(userScript)
// let config = WKWebViewConfiguration()
// config.userContentController = userContentController
// let webView = WKWebView(frame: .zero, configuration: config)
webView.navigationDelegate = self
webView.configuration.userContentController = userContentController
// Make sure in Info.plist you set `NSAllowsArbitraryLoads` to `YES` to load
// URLs with an HTTP connection. You can run a local server easily with services
// such as MAMP.
let htmlStr = "<html><body>Hello world - nojs</body></html>"
webView.loadHTMLString(htmlStr, baseURL: nil)
}
}
extension ViewController: WKScriptMessageHandler {
// Capture postMessage() calls inside loaded JavaScript from the webpage. Note that a Boolean
// will be parsed as a 0 for false and 1 for true in the message's body. See WebKit documentation:
// https://developer.apple.com/documentation/webkit/wkscriptmessage/1417901-body.
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if let messageBody = message.body as? String {
print(messageBody)
}
}
}
Another odd thing is that I do not seem to be able to create a simple WKWebView app that loads a page and displays it. These are all just simple tests and my main application is able to load/display webpages just fine using AlamoFire/loadHTMLString() to display pages, I just have not been able to inject the JS required.
Everything I've done in the conversion is quite straight forward and required little or no change with the exception of the assignment of the userContentController - so perhaps that's the problem? This example works just fine in iOS with his original sample as a prototype. https://github.com/rckim77/WKWebViewDemoApp/blob/master/WKWebViewDemoApp/ViewController.swift
I'm guessing there must be something very simple I'm missing here. Any help would be greatly appreciated!
Heres how I have set my WebView on Mac try something like this
import Cocoa
import WebKit
class ViewController: NSViewController {
#IBOutlet weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let javascript = """
function printStatement() {
try {
window.webkit.messageHandlers
.callbackHandler.postMessage({'payload': 'Hello World!'})
} catch(err) {
console.log('The native context does yet exist')
}
}
"""
let script = WKUserScript(
source: javascript,
injectionTime: WKUserScriptInjectionTime.atDocumentEnd,
forMainFrameOnly: true
)
webView.configuration.userContentController.add(
name: "callbackHandler"
)
webView.configuration.userContentController
.addUserScript(script)
webView.navigationDelegate = self
let html = """
<div onClick='javascript:printStatement()'>Print Statement</div>
"""
webView.loadHTMLString(html, nil)
}
}
extension ViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if(message.name == "callbackHandler") {
guard let body = message.body as? [String: Any] else {
print("could not convert message body to dictionary: \(message.body)")
return
}
guard let payload = body["payload"] as? String else {
print("Could not locate payload param in callback request")
return
}
print(payload)
}
}
}
Hopefully this answered your question and works if not let me know and i'll try figure it out!
Well, as it turns out a major part of the issue was that I needed to set the entitlements for both "App Sandbox" and "com.apple.security.files.user-selected.read-only" both to "no" in the WebTest.entitlements file.
This was not the case in previous versions of XCode (I'm on V10.1) and the default values basically disabled the WKWebView for what I was trying to do with it (ie, load a simple page either via URL or String)
However, Alex's fix did help once I got that solved... with a couple small tweaks (had to add 'self' to the userContentController.add() function. Also, I added my JS for it's original purpose which was to "push" to Swift every time the user changed the selection on the page.
Here's my final code:
import Cocoa
import WebKit
class ViewController: NSViewController, WKNavigationDelegate {
#IBOutlet var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let javascript = """
function printStatement() {
try {
var foo = window.getSelection().toString()
window.webkit.messageHandlers.callbackHandler.postMessage({'payload': foo})
} catch(err) {
console.log('The native context does yet exist')
}
}
function getSelectionAndSendMessage() {
try {
var currSelection = window.getSelection().toString()
window.webkit.messageHandlers.callbackHandler.postMessage({'payload': currSelection})
} catch(err) {
console.log('The native context does yet exist')
}
}
document.onmouseup = getSelectionAndSendMessage;
document.onkeyup = getSelectionAndSendMessage;
document.oncontextmenu = getSelectionAndSendMessage;
"""
let script = WKUserScript(
source: javascript,
injectionTime: WKUserScriptInjectionTime.atDocumentEnd,
forMainFrameOnly: true
)
webView.configuration.userContentController.add(self, name: "callbackHandler")
webView.configuration.userContentController.addUserScript(script)
webView.navigationDelegate = self
let html = """
<div onClick='javascript:printStatement()'>Print Statement</div>
This is some sample text to test select with
"""
webView.loadHTMLString(html, baseURL: nil)
}
}
extension ViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if(message.name == "callbackHandler") {
guard let body = message.body as? [String: Any] else {
print("could not convert message body to dictionary: \(message.body)")
return
}
guard let payload = body["payload"] as? String else {
print("Could not locate payload param in callback request")
return
}
print(payload)
}
}
}
Thanks Alex for all your fantastic support!