Skip to content
Browse files

support checking if app installed, closes #10

Simplify API for opening apps, as well as supporting more apps.
  • Loading branch information...
1 parent d4f3daa commit 6272e3549ea31cd876f5488f2485ee733c14e2e7 @Mazyod Mazyod committed
View
4 Appz/Appz.xcodeproj/project.pbxproj
@@ -150,9 +150,9 @@
826ACF171BF1BCF500B5FC5D /* Entity */ = {
isa = PBXGroup;
children = (
+ 826ACF5B1BF1E26B00B5FC5D /* ApplicationCaller.swift */,
826ACF181BF1BD1F00B5FC5D /* Applications.swift */,
826ACF1A1BF1BD7F00B5FC5D /* ExternalApplication.swift */,
- 826ACF5B1BF1E26B00B5FC5D /* ApplicationCaller.swift */,
82D9A0FA1C1E495D00EAC0ED /* Path.swift */,
);
path = Entity;
@@ -174,8 +174,8 @@
826ACF231BF1BFE100B5FC5D /* Extensions */ = {
isa = PBXGroup;
children = (
- 826ACF241BF1C00800B5FC5D /* UIApplication+Appz.swift */,
826ACF5D1BF1E4BE00B5FC5D /* NSExtensionContext+Appz.swift */,
+ 826ACF241BF1C00800B5FC5D /* UIApplication+Appz.swift */,
);
path = Extensions;
sourceTree = "<group>";
View
10 Appz/Appz/Apps/AppStore.swift
@@ -13,12 +13,12 @@ public extension Applications {
public struct AppStore: ExternalApplication {
+ public typealias ActionType = Applications.AppStore.Action
+
public let scheme = "itms-apps:"
- public let fallbackURL: String? = "http:"
- }
-
- public func appStore(action: AppStore.Action) -> Bool {
- return appCaller.launch(AppStore(), action: action)
+ public let fallbackURL = "http:"
+
+ public init() {}
}
}
View
10 Appz/Appz/Apps/Instagram.swift
@@ -13,12 +13,12 @@ public extension Applications {
public struct Instagram: ExternalApplication {
+ public typealias ActionType = Applications.Instagram.Action
+
public let scheme = "instagram:"
- public let fallbackURL: String? = "https://instagram.com/"
- }
-
- public func instagram(action: Instagram.Action) -> Bool {
- return appCaller.launch(Instagram(), action: action)
+ public let fallbackURL = "https://instagram.com/"
+
+ public init() {}
}
}
View
10 Appz/Appz/Apps/Mail.swift
@@ -13,12 +13,12 @@ public extension Applications {
public struct Mail: ExternalApplication {
+ public typealias ActionType = Applications.Mail.Action
+
public let scheme = "mailto:"
- public let fallbackURL: String? = ""
- }
-
- public func mail(action: Mail.Action) -> Bool {
- return appCaller.launch(Mail(), action: action)
+ public let fallbackURL = ""
+
+ public init() {}
}
}
View
10 Appz/Appz/Apps/Messages.swift
@@ -13,12 +13,12 @@ public extension Applications {
public struct Messages: ExternalApplication {
+ public typealias ActionType = Applications.Messages.Action
+
public let scheme = "sms:"
- public let fallbackURL: String? = ""
- }
-
- public func messages(action: Messages.Action) -> Bool {
- return appCaller.launch(Messages(), action: action)
+ public let fallbackURL = ""
+
+ public init() {}
}
}
View
10 Appz/Appz/Apps/Settings.swift
@@ -13,12 +13,12 @@ public extension Applications {
public struct AppSettings: ExternalApplication {
+ public typealias ActionType = Applications.AppSettings.Action
+
public let scheme = UIApplicationOpenSettingsURLString
- public let fallbackURL: String? = nil
- }
-
- func appSettings(action: AppSettings.Action) -> Bool {
- return appCaller.launch(AppSettings(), action: action)
+ public let fallbackURL = ""
+
+ public init() {}
}
}
View
10 Appz/Appz/Apps/Twitter.swift
@@ -13,12 +13,12 @@ public extension Applications {
public struct Twitter: ExternalApplication {
+ public typealias ActionType = Applications.Twitter.Action
+
public let scheme = "twitter:"
- public let fallbackURL: String? = "https://twitter.com/"
- }
-
- public func twitter(action: Twitter.Action) -> Bool {
- return appCaller.launch(Twitter(), action: action)
+ public let fallbackURL = "https://twitter.com/"
+
+ public init() {}
}
}
View
15 Appz/Appz/Entity/ApplicationCaller.swift
@@ -20,11 +20,16 @@ public protocol ApplicationCaller {
public extension ApplicationCaller {
- public var open: Applications {
- return Applications(appCaller: self)
+ public func canOpen<E: ExternalApplication>(externalApp: E) -> Bool {
+
+ if let baseURL = NSURL(string: externalApp.scheme) {
+ return canOpenURL(baseURL)
+ }
+
+ return false
}
- func launch(externalApp: ExternalApplication, action: ExternalApplicationAction) -> Bool {
+ public func open<E: ExternalApplication>(externalApp: E, action: E.ActionType) -> Bool {
let scheme = externalApp.scheme + "//"
let baseURL = NSURL(string: scheme)
@@ -36,9 +41,7 @@ public extension ApplicationCaller {
return openURL(url)
}
- if let fallbackURL = externalApp.fallbackURL,
- let url = paths.web.appendToURL(fallbackURL)
- {
+ if let url = paths.web.appendToURL(externalApp.fallbackURL) {
return openURL(url)
}
View
4 Appz/Appz/Entity/ExternalApplication.swift
@@ -14,8 +14,10 @@ import Foundation
*/
public protocol ExternalApplication {
+ typealias ActionType: ExternalApplicationAction
+
var scheme: String { get }
- var fallbackURL: String? { get }
+ var fallbackURL: String { get }
}
public struct ActionPaths {
View
2 Appz/AppzTests/AppsTests/SettingsTests.swift
@@ -18,7 +18,7 @@ class SettingsTests: XCTestCase {
let appSettings = Applications.AppSettings()
XCTAssertEqual(appSettings.scheme, "app-settings:")
- XCTAssertEqual(appSettings.fallbackURL, nil)
+ XCTAssertEqual(appSettings.fallbackURL, "")
}
func testOpenHome() {
View
14 Appz/AppzTests/EntityTests/ApplicationCallerTests.swift
@@ -14,8 +14,10 @@ class ApplicationCallerTests: XCTestCase {
private struct SampleApp: ExternalApplication {
+ typealias ActionType = SampleAction
+
let scheme = "test:"
- let fallbackURL: String? = "http://google.com/"
+ let fallbackURL = "http://google.com/"
}
private struct SampleAction: ExternalApplicationAction {
@@ -45,7 +47,7 @@ class ApplicationCallerTests: XCTestCase {
func testQuery() {
let sampleApp = SampleApp()
- appCallerMock.launch(sampleApp, action: SampleAction())
+ appCallerMock.open(sampleApp, action: SampleAction())
let expectedURL = NSURL(string: "\(sampleApp.scheme)//")
XCTAssertEqual(appCallerMock.queriedURLs[0], expectedURL)
@@ -58,7 +60,7 @@ class ApplicationCallerTests: XCTestCase {
sampleAction.paths.app = Path()
appCallerMock.canOpenURLs = true
- appCallerMock.launch(sampleApp, action: sampleAction)
+ appCallerMock.open(sampleApp, action: sampleAction)
let expectedURL = NSURL(string: "\(sampleApp.scheme)//")
XCTAssertEqual(appCallerMock.openedURLs[0], expectedURL)
@@ -70,7 +72,7 @@ class ApplicationCallerTests: XCTestCase {
let sampleAction = SampleAction()
appCallerMock.canOpenURLs = true
- appCallerMock.launch(sampleApp, action: sampleAction)
+ appCallerMock.open(sampleApp, action: sampleAction)
let expectedURL = sampleAction.paths.app.appendToURL("\(sampleApp.scheme)//")
XCTAssertEqual(appCallerMock.openedURLs[0], expectedURL)
@@ -82,9 +84,9 @@ class ApplicationCallerTests: XCTestCase {
let sampleAction = SampleAction()
appCallerMock.canOpenURLs = false
- appCallerMock.launch(sampleApp, action: sampleAction)
+ appCallerMock.open(sampleApp, action: sampleAction)
- let expectedURL = sampleAction.paths.web.appendToURL(sampleApp.fallbackURL!)
+ let expectedURL = sampleAction.paths.web.appendToURL(sampleApp.fallbackURL)
XCTAssertEqual(appCallerMock.openedURLs[0], expectedURL)
}
}
View
40 Playground/Playground.playground/Contents.swift
@@ -10,15 +10,15 @@ import Appz
//: Concise syntax to trigger deeplinking
let app = UIApplication.sharedApplication()
-app.open.appStore(.Account(id: "395107918"))
-app.open.twitter(.UserHandle("mazyod"))
-app.open.appSettings(.Open)
+app.canOpen(Applications.Instagram())
+app.open(Applications.AppStore(), action: .Account(id: "395107918"))
+app.open(Applications.AppSettings(), action: .Open)
//: Transparent web fallback
// In case the user doesn't have twitter installed, it will fallback to
// https://twitter.com/statuses/2
-app.open.twitter(.Status(id: "2"))
+app.open(Applications.Twitter(), action: .Status(id: "2"))
//: Add your own application
@@ -29,33 +29,29 @@ extension Applications {
// conforms to "ExternalApplication"
struct MyApp: ExternalApplication {
+ typealias ActionType = Applications.MyApp.Action
+
let scheme = "myapp:"
- let fallbackURL: String? = nil
- }
- // Add a function to easily access your app from
- // the application caller
- func myApp(action: MyApp.Action) -> Bool {
- return appCaller.launch(MyApp(), action: action)
+ let fallbackURL = ""
}
}
// Finally, you define the actions your app supports
extension Applications.MyApp {
- enum Action {
+ enum Action: ExternalApplicationAction {
+
case Open
- }
-}
-
-extension Applications.MyApp.Action: ExternalApplicationAction {
- // Each action should provide an app path and web path to be
- // added to the associated URL
- var paths: ActionPaths {
- switch self {
- case .Open:
- return ActionPaths()
+ // Each action should provide an app path and web path to be
+ // added to the associated URL
+ var paths: ActionPaths {
+
+ switch self {
+ case .Open:
+ return ActionPaths()
+ }
}
}
}
-app.open.myApp(.Open)
+app.open(Applications.MyApp(), action: .Open)
View
2 Playground/Playground.playground/contents.xcplayground
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<playground version='5.0' target-platform='ios' display-mode='raw' executeOnSourceChanges='false'>
+<playground version='5.0' target-platform='ios' display-mode='raw'>
<timeline fileName='timeline.xctimeline'/>
</playground>
View
48 README.md
@@ -40,9 +40,9 @@ __Concise syntax to trigger deep linking:__
```swift
let app = UIApplication.sharedApplication()
-app.open.appStore(.Account(id: "395107918"))
-app.open.twitter(.UserHandle("mazyod"))
-app.open.appSettings(.Open)
+app.canOpen(Applications.Instagram())
+app.open(Applications.AppStore(), action: .Account(id: "395107918"))
+app.open(Applications.AppSettings(), action: .Open)
```
__Transparent web fallback:__
@@ -50,49 +50,45 @@ __Transparent web fallback:__
```swift
// In case the user doesn't have twitter installed, it will fallback to
// https://twitter.com/statuses/2
-app.open.twitter(.Status(id: "2"))
+app.open(Applications.Twitter(), action: .Status(id: "2"))
```
__Add your applications:__
```swift
// Applications are recommended to be part of the
-// "Applicaitons" namespace
+// "Applications" namespace
extension Applications {
// Define your application as a type that
// conforms to "ExternalApplication"
struct MyApp: ExternalApplication {
+ typealias ActionType = Applications.MyApp.Action
+
let scheme = "myapp:"
- let fallbackURL: String? = nil
- }
- // Add a function to easily access your app from
- // the application caller
- func myApp(action: MyApp.Action) -> Bool {
- return appCaller.launch(MyApp(), action: action)
+ let fallbackURL = ""
}
}
-// Finally, you define the actions your app supports
+// Then, you define the actions your app supports
extension Applications.MyApp {
- enum Action {
+ enum Action: ExternalApplicationAction {
+
case Open
- }
-}
-extension Applications.MyApp.Action: ExternalApplicationAction {
- // Each action should provide an app path and web path to be
- // added to the associated URL
- var paths: ActionPaths {
-
- switch self {
- case .Open:
- return ActionPaths()
+ // Each action should provide an app path and web path to be
+ // added to the associated URL
+ var paths: ActionPaths {
+
+ switch self {
+ case .Open:
+ return ActionPaths()
+ }
}
}
}
-app.open.myApp(.Open)
+app.open(Applications.MyApp(), action: .Open)
```
__Supported Apps (for now!):__
@@ -100,10 +96,10 @@ __Supported Apps (for now!):__
App | Actions
----|--------
AppSettings | Open
-Mail | Compose
-Messages | SMS
AppStore | Developer, App
Instagram | Open, Camera, Media, Username, Location, Tag
+Mail | Compose
+Messages | SMS
Twitter | Status, UserHandle, UserId, List, Post, Search, Timeline, Mentions, Messages
## Getting Started

0 comments on commit 6272e35

Please sign in to comment.
Something went wrong with that request. Please try again.