phimage / callbackurlkit Goto Github PK
View Code? Open in Web Editor NEWImplementation of x-callback-url (Inter app communication) in swift
License: MIT License
Implementation of x-callback-url (Inter app communication) in swift
License: MIT License
I tried to use CallbackURLKit on a Today Extension Widget. When one button on the widget is pressed, it should invoke an action on the main application via a url action.
try? Manager.perform(action: "playcollection", urlScheme: "bingobongo", parameters: parameters)
This works when invoking the action from the extension with the device unlocked, but if the device is locked the system doesn't ask to unlock and simply disregards the action.
The problem comes from Manager.open(url: Foundation.URL) that calls: UIApplication.shared.openURL(url)
To let the device ask for the unlock code and then invoke the action, there's a similar method on NSExtensionContext: func open(_ URL: URL, completionHandler: ((Bool) -> Void)? = nil)
The same issue is descibed here:
http://stackoverflow.com/questions/26909821/ios-8-today-widget-and-locked-device
It would be useful to inject the current NSExtensionContext in a non-default Manager object, that when extensionContext is not nil will invoke this method instead of the one from UIApplication.
The x-success, x-failure and x-cancel callback URLs are not being constructed correctly; they are always empty strings. Thus, callbacks do not function properly.
In Manager.swift, line 199, it should be changed from:
xcuComponents.path = kResponse
to:
xcuComponents.path = "/" + kResponse
See the documentation for the NSURLComponents.URL property:
If the components object has an authority component (user, password, host, or port) and a path component, then the path must either begin with "/" or be an empty string. Otherwise, this property contains nil.
When a response must be posted the corresponding requestID is missing in the returned URL
How would you implement two way communication described in http://x-callback-url.com/examples/
Something like:
targetapp://x-callback-url/translate?
x-success=sourceapp://x-callback-url/acceptTranslation&
x-source=SourceApp&
x-error=sourceapp://x-callback-url/translationError&
word=Hello&
language=Spanish
Hello,
I've tried to run the Demo App but after running: "pod install" I get the following error:
andreasluca:SampleApp lucaandr$ pod install Analyzing dependencies Fetching podspec for
CallbackURLKitfrom
../CallbackURLKit.podspec[!] CocoaPods could not find compatible versions for pod "CallbackURLKit/GoogleChrome": In Podfile: CallbackURLKit/GoogleChrome (from
../CallbackURLKit.podspec`)
Specs satisfying the CallbackURLKit/GoogleChrome (from
../CallbackURLKit.podspec)
dependency were found, but they required a higher minimum deployment target.`
Do you know why is that?
Thank you
Hello,
As a proposal, I'd suggest the following:
Thanks (it's just a suggestion)!
The package.swift has been updated and is Accio compatible, but a new tag has not been pushed up. Can we get a new patch bump so Accio works? Thanks
Are you planning to release a new official version?
I think 'Manager' is too vague, not a huge issue but 'CallbackManager' or something would be more helpful.
In Manager.swift, in the Manager.sendRequest(_:)
method, the x-success
, x-failure
and x-cancel
parameters to the outgoing URL include their own query strings that include responseType
and requestID
parameters as well as any response parameters for a given action.
The ampersand characters (&) that delimit these embedded query strings should be percent-encoded; otherwise, they get parsed as query parameters of the outgoing URL, instead of the response URLs.
A typical URL that is built by this method looks like this, just before calling Manager.openURL(URL)
(in line 228):
otherapp://x-callback-url/actionName?x-source=MyAppName&
x-error=myapp://x-callback-url/response?responseType=error&requestID=9CE4D406-EB4E-4242-8ACD-14851A81A588&
x-cancel=myapp://x-callback-url/response?responseType=cancel&requestID=9CE4D406-EB4E-4242-8ACD-14851A81A588&
x-success=myapp://x-callback-url/response?responseType=success&requestID=9CE4D406-EB4E-4242-8ACD-14851A81A588
The problem is that the requestID
parameter gets stripped from the response URLs, thus the Manager.handleOpenURL(_:)
method fails to match up the response to its request (on line 77) and does not call the response handler closures.
I'm using your framework in a project running on the 10.13 beta and while it sends x-callbacks without a problem to an installed app (Ulysses, a writing program that has great x-callback support), I don't receive the callback. It's like my registration is ignored.
There's not much code...
The Ulysses App Client:
import Cocoa
import os.log
import CallbackURLKit
public class UlyssesClient: Client {
var ulyssesAuthSuccess = ""
var ulyssesAuthError = ""
var ulyssesScheme = "ulysses"
init() {
super.init(urlScheme:"ulysses")
ulyssesAuthSuccess = "fictivity://x-callback-url/auth-success"//.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
ulyssesAuthError = "fictivity://x-callback-url/auth-error"//.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
//os_log("%@", ulyssesURLString)
CallbackURLKit.register(action: "auth-success") { parameters, success, failure, cancel in
os_log("auth-success")
for parameter in parameters {
os_log("%@ = %@", parameter.key, parameter.value)
}
}
CallbackURLKit.register(action: "auth-error") { parameters, success, failure, cancel in
os_log("auth-error")
for parameter in parameters {
os_log("%@ = %@", parameter.key, parameter.value)
}
}
}
func authorize(onSuccess: SuccessCallback? = nil, onFailure: FailureCallback? = nil, onCancel: CancelCallback? = nil) throws {
try self.perform(action: "authorize", parameters: ["appname": "Fictivity", "x-success": ulyssesAuthSuccess, "x-error": ulyssesAuthError], onSuccess: onSuccess, onFailure: onFailure, onCancel: onCancel)
}
}
In AppDelegate:
func applicationDidFinishLaunching(_ aNotification: Notification) {
let manager = Manager.shared
manager.callbackURLScheme = Manager.urlSchemes?.first
Manager.shared.registerToURLEvent()
}
I did try changing the url scheme name, and confirmed that Ulysses give an error that there isn't any support for that url scheme. So, Ulysses is replying, the reply is just not propagating.
Any ideas?
I've successfully managed to send an action to Bear (MacOS, note taking app) using the code below that appends text to a note but I'm struggling with return parameters. I should be getting not contents back but onSuccess never gets called. Any thoughts on what I may be missing?
let manager = Manager.shared
manager.callbackURLScheme = "bear"
let client = Client(urlScheme: "bear")
do {
try client.perform(
action: "add-text",
parameters: ["title": "BearNote", "text" : "some text", "mode" : "append" ],
onSuccess: { parameters in
// never gets here
print( "Succeed" )
},
onFailure: { error in
print( "Fail" )
},
onCancel: {
print( "Cancelled" )
}
)
} catch {
print( "Error: \(error)" )
}
First off, thank you for this excellent package and the amount of ease and sanity it introduces when handling callback URLs!
It seems that either Apple or the Swift project made a breaking change in the latest Xcode beta release which affects CallbackURLKit. The change is documented here: https://forums.swift.org/t/set-application-extension-api-only-on-a-spm-package/39333/11
In short, it means that when compiling a Swift Package, it no longer matters if a main app or an extension is being targeted, but instead the code itself needs to declare whether a method is available for extensions or not, on top of everything else. In CallbackURLKit, this breaks at the point where the code tries to use UIApplication.shared.open(url: ...)
. While I and I'm sure many others probably think of this change as a bit reckless, it may be something that the code in the package needs to deal with.
The solution, thankfully, is relatively simple. The code needs to have the annotation @available(iOSApplicationExtension, unavailable)
around any method that cannot be called from an app extension. In the case of CallbackURLKit, it would just involve "babushka"ing that annotation on the method that opens URLs and the methods that use it in turn.
Please also see the discussion in the Apple Dev Forums here for reference: https://developer.apple.com/forums/thread/685103
I hope this is of some help. Thank you once again for the brilliant and super-useful package.
This is not so much of a problem, but more of a question (not sure where else to ask).
It's my first time writing swift and working with xcode so apologies if this looks trivial:
Here's my set up:
I have added a URL type to my app:
I created a custom client for the Bear app:
class BearClient: Client {
init() {
super.init(urlScheme: "bear")
}
public func search(query: String) {
let parameters = ["term": query]
do {
try self.perform(
action: "search",
parameters: parameters,
onSuccess: { parameters in
print(parameters?["notes"])
},
onFailure: {error in
print(error)
},
onCancel: {
print("cancelled")
}
)
} catch {
// NOOP
}
}
}
I have the manager initialized:
import SwiftUI
import CallbackURLKit
let manager = Manager.shared
@main
struct LookBackApp: App {
init() {
manager.callbackURLScheme = "lookback"
}
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL(perform: { url in
_ = manager.handleOpen(url: url)
})
}
}
}
When I call the client like so:
let client = BearClient()
client.search(query: "the")
the client runs (and the Bear app opens with the right search query) but the onSuccess
callback is never called.
What am I missing? I was assuming I don't create any specific handlers for success and error on the manager because that is not documented.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.