Skip to content
Browse files

Appz is born

  • Loading branch information...
0 parents commit c1d9904601779b2efc2fb2a1a0a19a945114496a @Mazyod Mazyod committed
223 .gitignore
@@ -0,0 +1,223 @@
+
+# PYSCRIPT-XCODE-IGNORE-START
+
+#########################
+# .gitignore file for Xcode4 and Xcode5 Source projects
+#
+# Apple bugs, waiting for Apple to fix/respond:
+#
+# 15564624 - what does the xccheckout file in Xcode5 do? Where's the documentation?
+#
+# Version 2.6
+# For latest version, see: http://stackoverflow.com/questions/49478/git-ignore-file-for-xcode-projects
+#
+# 2015 updates:
+# - Fixed typo in "xccheckout" line - thanks to @lyck for pointing it out!
+# - Fixed the .idea optional ignore. Thanks to @hashier for pointing this out
+# - Finally added "xccheckout" to the ignore. Apple still refuses to answer support requests about this, but in practice it seems you should ignore it.
+# - minor tweaks from Jona and Coeur (slightly more precise xc* filtering/names)
+# 2014 updates:
+# - appended non-standard items DISABLED by default (uncomment if you use those tools)
+# - removed the edit that an SO.com moderator made without bothering to ask me
+# - researched CocoaPods .lock more carefully, thanks to Gokhan Celiker
+# 2013 updates:
+# - fixed the broken "save personal Schemes"
+# - added line-by-line explanations for EVERYTHING (some were missing)
+#
+# NB: if you are storing "built" products, this WILL NOT WORK,
+# and you should use a different .gitignore (or none at all)
+# This file is for SOURCE projects, where there are many extra
+# files that we want to exclude
+#
+#########################
+
+#####
+# OS X temporary files that should never be committed
+#
+# c.f. http://www.westwind.com/reference/os-x/invisibles.html
+
+.DS_Store
+
+# c.f. http://www.westwind.com/reference/os-x/invisibles.html
+
+.Trashes
+
+# c.f. http://www.westwind.com/reference/os-x/invisibles.html
+
+*.swp
+
+#
+# *.lock - this is used and abused by many editors for many different things.
+# For the main ones I use (e.g. Eclipse), it should be excluded
+# from source-control, but YMMV.
+# (lock files are usually local-only file-synchronization on the local FS that should NOT go in git)
+# c.f. the "OPTIONAL" section at bottom though, for tool-specific variations!
+#
+# In particular, if you're using CocoaPods, you'll want to comment-out this line:
+*.lock
+
+
+#
+# profile - REMOVED temporarily (on double-checking, I can't find it in OS X docs?)
+#profile
+
+
+####
+# Xcode temporary files that should never be committed
+#
+# NB: NIB/XIB files still exist even on Storyboard projects, so we want this...
+
+*~.nib
+
+
+####
+# Xcode build files -
+#
+# NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "DerivedData"
+
+DerivedData/
+
+# NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "build"
+
+build/
+
+
+#####
+# Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups)
+#
+# This is complicated:
+#
+# SOMETIMES you need to put this file in version control.
+# Apple designed it poorly - if you use "custom executables", they are
+# saved in this file.
+# 99% of projects do NOT use those, so they do NOT want to version control this file.
+# ..but if you're in the 1%, comment out the line "*.pbxuser"
+
+# .pbxuser: http://lists.apple.com/archives/xcode-users/2004/Jan/msg00193.html
+
+*.pbxuser
+
+# .mode1v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html
+
+*.mode1v3
+
+# .mode2v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html
+
+*.mode2v3
+
+# .perspectivev3: http://stackoverflow.com/questions/5223297/xcode-projects-what-is-a-perspectivev3-file
+
+*.perspectivev3
+
+# NB: also, whitelist the default ones, some projects need to use these
+!default.pbxuser
+!default.mode1v3
+!default.mode2v3
+!default.perspectivev3
+
+
+####
+# Xcode 4 - semi-personal settings
+#
+# Apple Shared data that Apple put in the wrong folder
+# c.f. http://stackoverflow.com/a/19260712/153422
+# FROM ANSWER: Apple says "don't ignore it"
+# FROM COMMENTS: Apple is wrong; Apple code is too buggy to trust; there are no known negative side-effects to ignoring Apple's unofficial advice and instead doing the thing that actively fixes bugs in Xcode
+# Up to you, but ... current advice: ignore it.
+*.xccheckout
+
+#
+#
+# OPTION 1: ---------------------------------
+# throw away ALL personal settings (including custom schemes!
+# - unless they are "shared")
+# As per build/ and DerivedData/, this ought to have a trailing slash
+#
+# NB: this is exclusive with OPTION 2 below
+xcuserdata/
+
+# OPTION 2: ---------------------------------
+# get rid of ALL personal settings, but KEEP SOME OF THEM
+# - NB: you must manually uncomment the bits you want to keep
+#
+# NB: this *requires* git v1.8.2 or above; you may need to upgrade to latest OS X,
+# or manually install git over the top of the OS X version
+# NB: this is exclusive with OPTION 1 above
+#
+#xcuserdata/**/*
+
+# (requires option 2 above): Personal Schemes
+#
+#!xcuserdata/**/xcschemes/*
+
+####
+# XCode 4 workspaces - more detailed
+#
+# Workspaces are important! They are a core feature of Xcode - don't exclude them :)
+#
+# Workspace layout is quite spammy. For reference:
+#
+# /(root)/
+# /(project-name).xcodeproj/
+# project.pbxproj
+# /project.xcworkspace/
+# contents.xcworkspacedata
+# /xcuserdata/
+# /(your name)/xcuserdatad/
+# UserInterfaceState.xcuserstate
+# /xcshareddata/
+# /xcschemes/
+# (shared scheme name).xcscheme
+# /xcuserdata/
+# /(your name)/xcuserdatad/
+# (private scheme).xcscheme
+# xcschememanagement.plist
+#
+#
+
+####
+# Xcode 4 - Deprecated classes
+#
+# Allegedly, if you manually "deprecate" your classes, they get moved here.
+#
+# We're using source-control, so this is a "feature" that we do not want!
+
+*.moved-aside
+
+####
+# OPTIONAL: Some well-known tools that people use side-by-side with Xcode / iOS development
+#
+# NB: I'd rather not include these here, but gitignore's design is weak and doesn't allow
+# modular gitignore: you have to put EVERYTHING in one file.
+#
+# COCOAPODS:
+#
+# c.f. http://guides.cocoapods.org/using/using-cocoapods.html#what-is-a-podfilelock
+# c.f. http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
+#
+!Podfile.lock
+#
+# RUBY:
+#
+# c.f. http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/
+#
+!Gemfile.lock
+#
+# IDEA:
+#
+# c.f. https://www.jetbrains.com/objc/help/managing-projects-under-version-control.html?search=workspace.xml
+#
+#.idea/workspace.xml
+#
+# TEXTMATE:
+#
+# -- UNVERIFIED: c.f. http://stackoverflow.com/a/50283/153422
+#
+#tm_build_errors
+
+####
+# UNKNOWN: recommended by others, but I can't discover what these files are
+#
+
+# PYSCRIPT-XCODE-IGNORE-END
+
30 .travis.yml
@@ -0,0 +1,30 @@
+language: objective-c
+osx_image: xcode7.1
+env:
+ global:
+ - LC_CTYPE=en_US.UTF-8
+ - LANG=en_US.UTF-8
+ - WORKSPACE=Appz.xcworkspace
+ - IOS_FRAMEWORK_SCHEME="Appz-ios"
+ - IOS_SDK=iphonesimulator9.1
+ matrix:
+ - DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" RUN_TESTS="YES"
+ - DESTINATION="OS=8.2,name=iPhone 5" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" RUN_TESTS="YES"
+ - DESTINATION="OS=8.3,name=iPhone 5S" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" RUN_TESTS="YES"
+ - DESTINATION="OS=8.4,name=iPhone 6" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" RUN_TESTS="YES"
+ - DESTINATION="OS=9.1,name=iPhone 6S" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" RUN_TESTS="YES"
+before_install:
+- gem install xcpretty --no-rdoc --no-ri --no-document --quiet
+script:
+- set -o pipefail
+- xcodebuild -version
+- xcodebuild -showsdks
+- if [ $RUN_TESTS == "YES" ]; then xcodebuild -workspace "$WORKSPACE" -scheme "$SCHEME"
+ -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO
+ test | xcpretty -c; else xcodebuild -workspace "$WORKSPACE" -scheme "$SCHEME" -sdk
+ "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO build
+ | xcpretty -c; fi
+notifications:
+ email: false
+ slack:
+ secure: NhKT0y5VJ4NlgSXk3KZ+NdMnSFNi3c+VBhSBO7/sizMuFSRtUXNnRQ2MFsxO4uDtm/CIv0YPOQr2GpJsb7aRU/erpxKAaDjVtx3MM4xS34W+QhYDmF+P+T6phDRZwuuwsLVwVQrTiyNLULUrEExIh7tatcrYmYYBO3J8qqz884uPJOF0+roxi/2Gjm/CKhXS+vHvaBKS0sK47LtD3y6Tuvus5QPGd7fwUmhR53Yzpn8+7QW2tw4Yfzk9KyFrFX4NC3b6WpjKq0oL9JwNiKJvox+/MJY4moXh73IqE7iVOcDslWnCsos4QXMaGdugYiQrnvLGAQuVVLupeeF0V/QzVDBp5qb6fdtQc5mU6ijRelqhrRDRpop/yylVSIxEs0eFenPJtTNRZbAQI1qkJ7XRYHXpQH/armaF5nhi3gTbIgOu/0CFJsccQeBK8hIYyQFHswXsaxeY0pOjuHxgkrRLz82vjWnXf3jlxnxbCbYhsgRIp15dnxXt5G1zh6drQ4tuB9G/K6MhmB5MGhfkGsu66Gg0IsZAGDdNw8sA4QvK2hz9jzcDe1YiD4nlQq82JilZCnCG4m6WSALMvlyX7UZNcOkaJjb6vxj1KfwgMBv2kkyy7cuHmwWgDGVLwxqiPJ1P1camMV0iatKCGQEKBmvB8h2jEgH+S/dRHlUldVr5gAg=
10 Appz.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "group:Playground/Playground.playground">
+ </FileRef>
+ <FileRef
+ location = "group:Appz/Appz.xcodeproj">
+ </FileRef>
+</Workspace>
479 Appz/Appz.xcodeproj/project.pbxproj
@@ -0,0 +1,479 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 826ACEE21BF1B10A00B5FC5D /* Appz.h in Headers */ = {isa = PBXBuildFile; fileRef = 826ACEE11BF1B10A00B5FC5D /* Appz.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 826ACEE91BF1B10A00B5FC5D /* Appz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 826ACEDE1BF1B10A00B5FC5D /* Appz.framework */; };
+ 826ACF191BF1BD1F00B5FC5D /* AvailableApplications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF181BF1BD1F00B5FC5D /* AvailableApplications.swift */; };
+ 826ACF1B1BF1BD7F00B5FC5D /* ExternalApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF1A1BF1BD7F00B5FC5D /* ExternalApplication.swift */; };
+ 826ACF1E1BF1BEB000B5FC5D /* Twitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF1D1BF1BEB000B5FC5D /* Twitter.swift */; };
+ 826ACF201BF1BEB800B5FC5D /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF1F1BF1BEB800B5FC5D /* Settings.swift */; };
+ 826ACF221BF1BEBF00B5FC5D /* AppStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF211BF1BEBF00B5FC5D /* AppStore.swift */; };
+ 826ACF251BF1C00800B5FC5D /* UIApplication+Appz.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF241BF1C00800B5FC5D /* UIApplication+Appz.swift */; };
+ 826ACF271BF1C1CF00B5FC5D /* TwitterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF261BF1C1CF00B5FC5D /* TwitterTests.swift */; };
+ 826ACF291BF1C99600B5FC5D /* ApplicationCallerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF281BF1C99600B5FC5D /* ApplicationCallerTests.swift */; };
+ 826ACF5C1BF1E26B00B5FC5D /* ApplicationCaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF5B1BF1E26B00B5FC5D /* ApplicationCaller.swift */; };
+ 826ACF5E1BF1E4BE00B5FC5D /* NSExtensionContext+Appz.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF5D1BF1E4BE00B5FC5D /* NSExtensionContext+Appz.swift */; };
+ 827EF6171BF2756C000B1607 /* ApplicationCallerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827EF6161BF2756C000B1607 /* ApplicationCallerMock.swift */; };
+ 827EF61B1BF2EAA0000B1607 /* SettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827EF61A1BF2EAA0000B1607 /* SettingsTests.swift */; };
+ 827EF61D1BF2EBAC000B1607 /* AppStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827EF61C1BF2EBAC000B1607 /* AppStoreTests.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 826ACEEA1BF1B10A00B5FC5D /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 826ACED51BF1B10A00B5FC5D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 826ACEDD1BF1B10A00B5FC5D;
+ remoteInfo = Appz;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 826ACEDE1BF1B10A00B5FC5D /* Appz.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Appz.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 826ACEE11BF1B10A00B5FC5D /* Appz.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Appz.h; sourceTree = "<group>"; };
+ 826ACEE31BF1B10A00B5FC5D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 826ACEE81BF1B10A00B5FC5D /* AppzTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AppzTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 826ACEEF1BF1B10A00B5FC5D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 826ACF181BF1BD1F00B5FC5D /* AvailableApplications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvailableApplications.swift; sourceTree = "<group>"; };
+ 826ACF1A1BF1BD7F00B5FC5D /* ExternalApplication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExternalApplication.swift; sourceTree = "<group>"; };
+ 826ACF1D1BF1BEB000B5FC5D /* Twitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Twitter.swift; sourceTree = "<group>"; };
+ 826ACF1F1BF1BEB800B5FC5D /* Settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
+ 826ACF211BF1BEBF00B5FC5D /* AppStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppStore.swift; sourceTree = "<group>"; };
+ 826ACF241BF1C00800B5FC5D /* UIApplication+Appz.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+Appz.swift"; sourceTree = "<group>"; };
+ 826ACF261BF1C1CF00B5FC5D /* TwitterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TwitterTests.swift; sourceTree = "<group>"; };
+ 826ACF281BF1C99600B5FC5D /* ApplicationCallerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationCallerTests.swift; sourceTree = "<group>"; };
+ 826ACF5B1BF1E26B00B5FC5D /* ApplicationCaller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationCaller.swift; sourceTree = "<group>"; };
+ 826ACF5D1BF1E4BE00B5FC5D /* NSExtensionContext+Appz.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSExtensionContext+Appz.swift"; sourceTree = "<group>"; };
+ 827EF6161BF2756C000B1607 /* ApplicationCallerMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationCallerMock.swift; sourceTree = "<group>"; };
+ 827EF61A1BF2EAA0000B1607 /* SettingsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTests.swift; sourceTree = "<group>"; };
+ 827EF61C1BF2EBAC000B1607 /* AppStoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppStoreTests.swift; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 826ACEDA1BF1B10A00B5FC5D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 826ACEE51BF1B10A00B5FC5D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 826ACEE91BF1B10A00B5FC5D /* Appz.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 826ACED41BF1B10A00B5FC5D = {
+ isa = PBXGroup;
+ children = (
+ 826ACEE01BF1B10A00B5FC5D /* Appz */,
+ 826ACEEC1BF1B10A00B5FC5D /* AppzTests */,
+ 826ACEDF1BF1B10A00B5FC5D /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ 826ACEDF1BF1B10A00B5FC5D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 826ACEDE1BF1B10A00B5FC5D /* Appz.framework */,
+ 826ACEE81BF1B10A00B5FC5D /* AppzTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 826ACEE01BF1B10A00B5FC5D /* Appz */ = {
+ isa = PBXGroup;
+ children = (
+ 826ACF231BF1BFE100B5FC5D /* Extensions */,
+ 826ACF1C1BF1BE9C00B5FC5D /* Apps */,
+ 826ACF171BF1BCF500B5FC5D /* Entity */,
+ 826ACEE11BF1B10A00B5FC5D /* Appz.h */,
+ 826ACEE31BF1B10A00B5FC5D /* Info.plist */,
+ );
+ path = Appz;
+ sourceTree = "<group>";
+ };
+ 826ACEEC1BF1B10A00B5FC5D /* AppzTests */ = {
+ isa = PBXGroup;
+ children = (
+ 827EF6151BF2751C000B1607 /* Mocks */,
+ 826ACF281BF1C99600B5FC5D /* ApplicationCallerTests.swift */,
+ 826ACF261BF1C1CF00B5FC5D /* TwitterTests.swift */,
+ 827EF61A1BF2EAA0000B1607 /* SettingsTests.swift */,
+ 827EF61C1BF2EBAC000B1607 /* AppStoreTests.swift */,
+ 826ACEEF1BF1B10A00B5FC5D /* Info.plist */,
+ );
+ path = AppzTests;
+ sourceTree = "<group>";
+ };
+ 826ACF171BF1BCF500B5FC5D /* Entity */ = {
+ isa = PBXGroup;
+ children = (
+ 826ACF181BF1BD1F00B5FC5D /* AvailableApplications.swift */,
+ 826ACF1A1BF1BD7F00B5FC5D /* ExternalApplication.swift */,
+ 826ACF5B1BF1E26B00B5FC5D /* ApplicationCaller.swift */,
+ );
+ path = Entity;
+ sourceTree = "<group>";
+ };
+ 826ACF1C1BF1BE9C00B5FC5D /* Apps */ = {
+ isa = PBXGroup;
+ children = (
+ 826ACF1D1BF1BEB000B5FC5D /* Twitter.swift */,
+ 826ACF1F1BF1BEB800B5FC5D /* Settings.swift */,
+ 826ACF211BF1BEBF00B5FC5D /* AppStore.swift */,
+ );
+ path = Apps;
+ sourceTree = "<group>";
+ };
+ 826ACF231BF1BFE100B5FC5D /* Extensions */ = {
+ isa = PBXGroup;
+ children = (
+ 826ACF241BF1C00800B5FC5D /* UIApplication+Appz.swift */,
+ 826ACF5D1BF1E4BE00B5FC5D /* NSExtensionContext+Appz.swift */,
+ );
+ path = Extensions;
+ sourceTree = "<group>";
+ };
+ 827EF6151BF2751C000B1607 /* Mocks */ = {
+ isa = PBXGroup;
+ children = (
+ 827EF6161BF2756C000B1607 /* ApplicationCallerMock.swift */,
+ );
+ path = Mocks;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 826ACEDB1BF1B10A00B5FC5D /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 826ACEE21BF1B10A00B5FC5D /* Appz.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 826ACEDD1BF1B10A00B5FC5D /* Appz-ios */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 826ACEF21BF1B10A00B5FC5D /* Build configuration list for PBXNativeTarget "Appz-ios" */;
+ buildPhases = (
+ 826ACED91BF1B10A00B5FC5D /* Sources */,
+ 826ACEDA1BF1B10A00B5FC5D /* Frameworks */,
+ 826ACEDB1BF1B10A00B5FC5D /* Headers */,
+ 826ACEDC1BF1B10A00B5FC5D /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "Appz-ios";
+ productName = Appz;
+ productReference = 826ACEDE1BF1B10A00B5FC5D /* Appz.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+ 826ACEE71BF1B10A00B5FC5D /* AppzTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 826ACEF51BF1B10A00B5FC5D /* Build configuration list for PBXNativeTarget "AppzTests" */;
+ buildPhases = (
+ 826ACEE41BF1B10A00B5FC5D /* Sources */,
+ 826ACEE51BF1B10A00B5FC5D /* Frameworks */,
+ 826ACEE61BF1B10A00B5FC5D /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 826ACEEB1BF1B10A00B5FC5D /* PBXTargetDependency */,
+ );
+ name = AppzTests;
+ productName = AppzTests;
+ productReference = 826ACEE81BF1B10A00B5FC5D /* AppzTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 826ACED51BF1B10A00B5FC5D /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastSwiftUpdateCheck = 0710;
+ LastUpgradeCheck = 0710;
+ ORGANIZATIONNAME = kitz;
+ TargetAttributes = {
+ 826ACEDD1BF1B10A00B5FC5D = {
+ CreatedOnToolsVersion = 7.1;
+ };
+ 826ACEE71BF1B10A00B5FC5D = {
+ CreatedOnToolsVersion = 7.1;
+ };
+ };
+ };
+ buildConfigurationList = 826ACED81BF1B10A00B5FC5D /* Build configuration list for PBXProject "Appz" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 826ACED41BF1B10A00B5FC5D;
+ productRefGroup = 826ACEDF1BF1B10A00B5FC5D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 826ACEDD1BF1B10A00B5FC5D /* Appz-ios */,
+ 826ACEE71BF1B10A00B5FC5D /* AppzTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 826ACEDC1BF1B10A00B5FC5D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 826ACEE61BF1B10A00B5FC5D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 826ACED91BF1B10A00B5FC5D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 826ACF1B1BF1BD7F00B5FC5D /* ExternalApplication.swift in Sources */,
+ 826ACF5E1BF1E4BE00B5FC5D /* NSExtensionContext+Appz.swift in Sources */,
+ 826ACF221BF1BEBF00B5FC5D /* AppStore.swift in Sources */,
+ 826ACF1E1BF1BEB000B5FC5D /* Twitter.swift in Sources */,
+ 826ACF201BF1BEB800B5FC5D /* Settings.swift in Sources */,
+ 826ACF191BF1BD1F00B5FC5D /* AvailableApplications.swift in Sources */,
+ 826ACF5C1BF1E26B00B5FC5D /* ApplicationCaller.swift in Sources */,
+ 826ACF251BF1C00800B5FC5D /* UIApplication+Appz.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 826ACEE41BF1B10A00B5FC5D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 826ACF291BF1C99600B5FC5D /* ApplicationCallerTests.swift in Sources */,
+ 827EF6171BF2756C000B1607 /* ApplicationCallerMock.swift in Sources */,
+ 827EF61D1BF2EBAC000B1607 /* AppStoreTests.swift in Sources */,
+ 827EF61B1BF2EAA0000B1607 /* SettingsTests.swift in Sources */,
+ 826ACF271BF1C1CF00B5FC5D /* TwitterTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 826ACEEB1BF1B10A00B5FC5D /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 826ACEDD1BF1B10A00B5FC5D /* Appz-ios */;
+ targetProxy = 826ACEEA1BF1B10A00B5FC5D /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 826ACEF01BF1B10A00B5FC5D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Debug;
+ };
+ 826ACEF11BF1B10A00B5FC5D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Release;
+ };
+ 826ACEF31BF1B10A00B5FC5D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ DEFINES_MODULE = YES;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ INFOPLIST_FILE = Appz/Info.plist;
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = io.kitz.Appz;
+ PRODUCT_NAME = Appz;
+ SKIP_INSTALL = YES;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ 826ACEF41BF1B10A00B5FC5D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ DEFINES_MODULE = YES;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ INFOPLIST_FILE = Appz/Info.plist;
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = io.kitz.Appz;
+ PRODUCT_NAME = Appz;
+ SKIP_INSTALL = YES;
+ };
+ name = Release;
+ };
+ 826ACEF61BF1B10A00B5FC5D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ INFOPLIST_FILE = AppzTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = io.kitz.AppzTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ 826ACEF71BF1B10A00B5FC5D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ INFOPLIST_FILE = AppzTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = io.kitz.AppzTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 826ACED81BF1B10A00B5FC5D /* Build configuration list for PBXProject "Appz" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 826ACEF01BF1B10A00B5FC5D /* Debug */,
+ 826ACEF11BF1B10A00B5FC5D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 826ACEF21BF1B10A00B5FC5D /* Build configuration list for PBXNativeTarget "Appz-ios" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 826ACEF31BF1B10A00B5FC5D /* Debug */,
+ 826ACEF41BF1B10A00B5FC5D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 826ACEF51BF1B10A00B5FC5D /* Build configuration list for PBXNativeTarget "AppzTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 826ACEF61BF1B10A00B5FC5D /* Debug */,
+ 826ACEF71BF1B10A00B5FC5D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 826ACED51BF1B10A00B5FC5D /* Project object */;
+}
100 Appz/Appz.xcodeproj/xcshareddata/xcschemes/Appz-ios.xcscheme
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0710"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "826ACEDD1BF1B10A00B5FC5D"
+ BuildableName = "Appz-ios.framework"
+ BlueprintName = "Appz-ios"
+ ReferencedContainer = "container:Appz.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ codeCoverageEnabled = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "826ACEE71BF1B10A00B5FC5D"
+ BuildableName = "AppzTests.xctest"
+ BlueprintName = "AppzTests"
+ ReferencedContainer = "container:Appz.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "826ACEDD1BF1B10A00B5FC5D"
+ BuildableName = "Appz-ios.framework"
+ BlueprintName = "Appz-ios"
+ ReferencedContainer = "container:Appz.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "826ACEDD1BF1B10A00B5FC5D"
+ BuildableName = "Appz-ios.framework"
+ BlueprintName = "Appz-ios"
+ ReferencedContainer = "container:Appz.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "826ACEDD1BF1B10A00B5FC5D"
+ BuildableName = "Appz-ios.framework"
+ BlueprintName = "Appz-ios"
+ ReferencedContainer = "container:Appz.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
50 Appz/Appz/Apps/AppStore.swift
@@ -0,0 +1,50 @@
+//
+// AppStore.swift
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/9/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+import Foundation
+
+
+public extension AvailableApplications {
+
+ public struct AppStore: ExternalApplication {
+
+ public let scheme = "itms-apps:"
+ public let fallbackURL: String? = "http:"
+ }
+
+ public func appStore(action: AppStore.Action) -> Bool {
+ return appCaller.launch(AppStore(), action: action)
+ }
+}
+
+// MARK: - Actions
+
+public extension AvailableApplications.AppStore {
+
+ public enum Action {
+
+ case Account(id: String)
+ case App(id: String)
+ }
+}
+
+
+extension AvailableApplications.AppStore.Action: ExternalApplicationAction {
+
+ public var path: String {
+
+ switch self {
+ case .Account(let id):
+ return "itunes.apple.com/developer/id\(id)"
+
+ case .App(let id):
+ return "itunes.apple.com/apps/id\(id)"
+ }
+ }
+}
+
35 Appz/Appz/Apps/Settings.swift
@@ -0,0 +1,35 @@
+//
+// Settings.swift
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/9/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+import UIKit
+
+
+public extension AvailableApplications {
+
+ public struct AppSettings: ExternalApplication {
+
+ public let scheme = UIApplicationOpenSettingsURLString
+ public let fallbackURL: String? = nil
+ }
+
+ func appSettings(action: AppSettings.Action) -> Bool {
+ return appCaller.launch(AppSettings(), action: action)
+ }
+}
+
+// MARK: - Actions
+
+public extension AvailableApplications.AppSettings {
+
+ public enum Action {
+
+ case Open
+ }
+}
+
+extension AvailableApplications.AppSettings.Action: ExternalApplicationAction {}
119 Appz/Appz/Apps/Twitter.swift
@@ -0,0 +1,119 @@
+//
+// Twitter.swift
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/9/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+import Foundation
+
+
+public extension AvailableApplications {
+
+ public struct Twitter: ExternalApplication {
+
+ public let scheme = "twitter:"
+ public let fallbackURL: String? = "https://twitter.com/"
+ }
+
+ public func twitter(action: Twitter.Action) -> Bool {
+ return appCaller.launch(Twitter(), action: action)
+ }
+}
+
+// MARK: - Actions
+
+public extension AvailableApplications.Twitter {
+
+ public enum Action {
+
+ case Status(id: String)
+ case UserHandle(String)
+ case UserId(String)
+ case List(handle: String, slug: String)
+ case Post(message: String, repliedStatusId: String?)
+ case Search(query: String)
+ case Timeline
+ case Mentions
+ case Messages
+ }
+}
+
+extension AvailableApplications.Twitter.Action: ExternalApplicationAction {
+
+ public var path: String {
+
+ switch self {
+ case .Status(let id):
+ return "status?id=\(id)"
+
+ case .UserHandle(let handle):
+ return "user?screen_name=\(handle)"
+
+ case .UserId(let id):
+ return "user?id=\(id)"
+
+ case .Post(let message, let statusId):
+
+ var path = "post?message=\(escape(message))"
+ if let statusId = statusId {
+ path += "&in_reply_to_status_id=\(statusId)"
+ }
+ return path
+
+ case .List(let handle, let slug):
+ return "list?screen_name=\(handle)&slug=\(escape(slug))"
+
+ case .Search(let query):
+ return "search?query=\(escape(query))"
+
+ case .Timeline:
+ return "timeline"
+
+ case .Mentions:
+ return "mentions"
+
+ case .Messages:
+ return "messages"
+ }
+ }
+
+ public var fallbackPath: String? {
+
+ switch self {
+ case .Status(let id):
+ return "statuses/\(id)"
+
+ case .UserHandle(let handle):
+ return handle
+
+ case .UserId(let id):
+ return "intent/user?user_id=\(id)"
+
+ case .Post(let message, let statusId):
+
+ var path = "intent/tweet?text=\(escape(message))"
+ if let statusId = statusId {
+ path += "&in_reply_to=\(statusId)"
+ }
+ return path
+
+ case .List(let handle, let slug):
+ return "\(handle)/lists/\(slug)"
+
+ case .Search(let query):
+ return "search?q=\(escape(query))"
+
+ case .Timeline:
+ return "" // Just open twitter
+
+ case .Mentions:
+ return "mentions"
+
+ case .Messages:
+ return "messages"
+ }
+ }
+}
+
19 Appz/Appz/Appz.h
@@ -0,0 +1,19 @@
+//
+// Appz.h
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/9/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+//! Project version number for Appz.
+FOUNDATION_EXPORT double AppzVersionNumber;
+
+//! Project version string for Appz.
+FOUNDATION_EXPORT const unsigned char AppzVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import <Appz/PublicHeader.h>
+
+
48 Appz/Appz/Entity/ApplicationCaller.swift
@@ -0,0 +1,48 @@
+//
+// ApplicationCaller.swift
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/10/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+import Foundation
+
+
+/** Encapsulate the object which launches the apps. Useful for
+ UIApplication, NSExtensionContext, and testing.
+*/
+public protocol ApplicationCaller {
+
+ func canOpenURL(url: NSURL) -> Bool
+ func openURL(url: NSURL) -> Bool
+}
+
+public extension ApplicationCaller {
+
+ public var open: AvailableApplications {
+ return AvailableApplications(appCaller: self)
+ }
+
+ func launch(externalApp: ExternalApplication, action: ExternalApplicationAction) -> Bool {
+
+ let fallbackPath = action.fallbackPath ?? action.path
+
+ let scheme = (externalApp.scheme ?? "") + "//"
+ let baseURL = NSURL(string: scheme)
+
+ if let url = baseURL where canOpenURL(url),
+ let fullURL = NSURL(string: scheme + action.path)
+ {
+ return openURL(fullURL)
+ }
+
+ if let fallbackURL = externalApp.fallbackURL,
+ let url = NSURL(string: fallbackURL + fallbackPath)
+ {
+ return openURL(url)
+ }
+
+ return false
+ }
+}
21 Appz/Appz/Entity/AvailableApplications.swift
@@ -0,0 +1,21 @@
+//
+// AvailableApplications.swift
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/9/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+import Foundation
+
+
+/** Base for aggregating the available applications.
+ */
+public struct AvailableApplications {
+
+ public let appCaller: ApplicationCaller
+
+ init(appCaller: ApplicationCaller) {
+ self.appCaller = appCaller
+ }
+}
40 Appz/Appz/Entity/ExternalApplication.swift
@@ -0,0 +1,40 @@
+//
+// ExternalApplication.swift
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/9/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+import Foundation
+
+
+/** Protocol for grouping the external application functionality.
+ For now, it's as simple as calling openURL
+ */
+public protocol ExternalApplication {
+
+ var scheme: String { get }
+ var fallbackURL: String? { get }
+}
+
+public protocol ExternalApplicationAction {
+
+ var path: String { get }
+ var fallbackPath: String? { get }
+}
+
+public extension ExternalApplicationAction {
+
+ var path: String {
+ return ""
+ }
+
+ var fallbackPath: String? {
+ return nil
+ }
+
+ func escape(string: String) -> String {
+ return string.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) ?? ""
+ }
+}
24 Appz/Appz/Extensions/NSExtensionContext+Appz.swift
@@ -0,0 +1,24 @@
+//
+// NSExtensionContext+Appz.swift
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/10/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+import Foundation
+
+
+extension NSExtensionContext: ApplicationCaller {
+
+ /** Unconditionally fail to the failover code. See rdar://18107612
+ */
+ public func canOpenURL(url: NSURL) -> Bool {
+ return false
+ }
+
+ public func openURL(url: NSURL) -> Bool {
+ openURL(url, completionHandler: nil)
+ return true // maybe use a semaphore instead
+ }
+}
12 Appz/Appz/Extensions/UIApplication+Appz.swift
@@ -0,0 +1,12 @@
+//
+// UIApplication+Appz.swift
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/9/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+import UIKit
+
+
+extension UIApplication: ApplicationCaller {}
26 Appz/Appz/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>$(CURRENT_PROJECT_VERSION)</string>
+ <key>NSPrincipalClass</key>
+ <string></string>
+</dict>
+</plist>
41 Appz/AppzTests/AppStoreTests.swift
@@ -0,0 +1,41 @@
+//
+// AppStoreTests.swift
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/10/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+import XCTest
+@testable import Appz
+
+
+class AppStoreTests: XCTestCase {
+
+ let appCaller = ApplicationCallerMock()
+
+ func testConfiguration() {
+
+ let appStore = AvailableApplications.AppStore()
+ XCTAssertEqual(appStore.scheme, "itms-apps:")
+ XCTAssertEqual(appStore.fallbackURL, "http:")
+ }
+
+ func testOpenApp() {
+
+ let appId = "395107915"
+ let action = AvailableApplications.AppStore.Action.App(id: appId)
+
+ XCTAssertEqual(action.path, "itunes.apple.com/apps/id\(appId)")
+ XCTAssertEqual(action.fallbackPath, nil)
+ }
+
+ func testOpenAccount() {
+
+ let accountId = "395107918"
+ let action = AvailableApplications.AppStore.Action.Account(id: accountId)
+
+ XCTAssertEqual(action.path, "itunes.apple.com/developer/id\(accountId)")
+ XCTAssertEqual(action.fallbackPath, nil)
+ }
+}
96 Appz/AppzTests/ApplicationCallerTests.swift
@@ -0,0 +1,96 @@
+//
+// ApplicationCallerTests.swift
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/9/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+import XCTest
+@testable import Appz
+
+
+class ApplicationCallerTests: XCTestCase {
+
+ private struct SampleApp: ExternalApplication {
+
+ let scheme = "test:"
+ let fallbackURL: String? = "http://google.com/"
+ }
+
+ private struct SampleAction: ExternalApplicationAction {
+
+ var path = "search/something?param=5"
+ var fallbackPath: String? = "find/otherThing?param=1"
+ }
+
+
+ private let appCallerMock = ApplicationCallerMock()
+
+
+ override func setUp() {
+ super.setUp()
+
+ appCallerMock.clear()
+ }
+
+ func testQuery() {
+
+ let sampleApp = SampleApp()
+ appCallerMock.launch(sampleApp, action: SampleAction())
+
+ let expectedURL = NSURL(string: "\(sampleApp.scheme)//")
+ XCTAssertEqual(appCallerMock.queriedURLs[0], expectedURL)
+ }
+
+ func testOpenEmptyPath() {
+
+ let sampleApp = SampleApp()
+ var sampleAction = SampleAction()
+ sampleAction.path = ""
+
+ appCallerMock.canOpenURLs = true
+ appCallerMock.launch(sampleApp, action: sampleAction)
+
+ let expectedURL = NSURL(string: "\(sampleApp.scheme)//")
+ XCTAssertEqual(appCallerMock.openedURLs[0], expectedURL)
+ }
+
+ func testOpenPath() {
+
+ let sampleApp = SampleApp()
+ let sampleAction = SampleAction()
+
+ appCallerMock.canOpenURLs = true
+ appCallerMock.launch(sampleApp, action: sampleAction)
+
+ let expectedURL = NSURL(string: "\(sampleApp.scheme)//" + sampleAction.path)
+ XCTAssertEqual(appCallerMock.openedURLs[0], expectedURL)
+ }
+
+ func testOpenFallbackPath() {
+
+ let sampleApp = SampleApp()
+ let sampleAction = SampleAction()
+
+ appCallerMock.canOpenURLs = false
+ appCallerMock.launch(sampleApp, action: sampleAction)
+
+ let expectedURL = NSURL(string: sampleApp.fallbackURL! + sampleAction.fallbackPath!)
+ XCTAssertEqual(appCallerMock.openedURLs[0], expectedURL)
+ }
+
+ func testOpenNilFallbackPath() {
+
+ let sampleApp = SampleApp()
+ var sampleAction = SampleAction()
+ sampleAction.fallbackPath = nil
+
+ appCallerMock.canOpenURLs = false
+ appCallerMock.launch(sampleApp, action: sampleAction)
+
+ // it should use path as the fallbackPath
+ let expectedURL = NSURL(string: sampleApp.fallbackURL! + sampleAction.path)
+ XCTAssertEqual(appCallerMock.openedURLs[0], expectedURL)
+ }
+}
24 Appz/AppzTests/Info.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>
34 Appz/AppzTests/Mocks/ApplicationCallerMock.swift
@@ -0,0 +1,34 @@
+//
+// ApplicationCallerMock.swift
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/10/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+import Foundation
+@testable import Appz
+
+
+class ApplicationCallerMock: ApplicationCaller {
+
+ var canOpenURLs = true
+
+ var queriedURLs = [NSURL]()
+ var openedURLs = [NSURL]()
+
+ func openURL(url: NSURL) -> Bool {
+ openedURLs.append(url)
+ return true
+ }
+
+ func canOpenURL(url: NSURL) -> Bool {
+ queriedURLs.append(url)
+ return canOpenURLs
+ }
+
+ func clear() {
+ queriedURLs.removeAll()
+ openedURLs.removeAll()
+ }
+}
30 Appz/AppzTests/SettingsTests.swift
@@ -0,0 +1,30 @@
+//
+// SettingsTests.swift
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/10/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+import XCTest
+@testable import Appz
+
+
+class SettingsTests: XCTestCase {
+
+ let appCaller = ApplicationCallerMock()
+
+ func testConfiguration() {
+
+ let appSettings = AvailableApplications.AppSettings()
+ XCTAssertEqual(appSettings.scheme, "app-settings:")
+ XCTAssertEqual(appSettings.fallbackURL, nil)
+ }
+
+ func testOpenHome() {
+
+ let action = AvailableApplications.AppSettings.Action.Open
+ XCTAssertEqual(action.path, "")
+ XCTAssertEqual(action.fallbackPath, nil)
+ }
+}
41 Appz/AppzTests/TwitterTests.swift
@@ -0,0 +1,41 @@
+//
+// TwitterTests.swift
+// Appz
+//
+// Created by Mazyad Alabduljaleel on 11/9/15.
+// Copyright © 2015 kitz. All rights reserved.
+//
+
+import XCTest
+@testable import Appz
+
+
+class TwitterTests: XCTestCase {
+
+ let appCaller = ApplicationCallerMock()
+
+ func testConfiguration() {
+
+ let twitter = AvailableApplications.Twitter()
+ XCTAssertEqual(twitter.scheme, "twitter:")
+ XCTAssertEqual(twitter.fallbackURL, "https://twitter.com/")
+ }
+
+ func testOpenUserHandle() {
+
+ let handle = "mazyod"
+ let action = AvailableApplications.Twitter.Action.UserHandle(handle)
+
+ XCTAssertEqual(action.path, "user?screen_name=\(handle)")
+ XCTAssertEqual(action.fallbackPath, handle)
+ }
+
+ func testOpenStatus() {
+
+ let statusId = "663797797234323456"
+ let action = AvailableApplications.Twitter.Action.Status(id: statusId)
+
+ XCTAssertEqual(action.path, "status?id=\(statusId)")
+ XCTAssertEqual(action.fallbackPath, "statuses/\(statusId)")
+ }
+}
21 LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Kitz
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
37 Playground/Playground.playground/Contents.swift
@@ -0,0 +1,37 @@
+//: Playground - noun: a place where people can play
+
+import UIKit
+import Appz
+
+//: ## Features
+//: Concise syntax to trigger deeplinking
+
+let app = UIApplication.sharedApplication()
+app.open.appStore(.Account(id: "395107918"))
+app.open.twitter(.UserHandle("mazyod"))
+app.open.appSettings(.Open)
+
+//: Add your own application
+
+extension AvailableApplications {
+
+ struct MyApp: ExternalApplication {
+
+ let scheme = "myapp:"
+ let fallbackURL: String? = nil
+ }
+
+ func myApp(action: MyApp.Action) -> Bool {
+ return appCaller.launch(MyApp(), action: action)
+ }
+}
+
+extension AvailableApplications.MyApp {
+
+ enum Action: ExternalApplicationAction {
+
+ case Open
+ }
+}
+
+app.open.myApp(.Open)
430 Playground/Playground.playground/Sources/Appz.xcodeproj/project.pbxproj
@@ -0,0 +1,430 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 826ACEE21BF1B10A00B5FC5D /* Appz.h in Headers */ = {isa = PBXBuildFile; fileRef = 826ACEE11BF1B10A00B5FC5D /* Appz.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 826ACEE91BF1B10A00B5FC5D /* Appz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 826ACEDE1BF1B10A00B5FC5D /* Appz.framework */; };
+ 826ACEEE1BF1B10A00B5FC5D /* AppzTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACEED1BF1B10A00B5FC5D /* AppzTests.swift */; };
+ 826ACF191BF1BD1F00B5FC5D /* AvailableApplications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF181BF1BD1F00B5FC5D /* AvailableApplications.swift */; };
+ 826ACF1B1BF1BD7F00B5FC5D /* ApplicationAccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF1A1BF1BD7F00B5FC5D /* ApplicationAccess.swift */; };
+ 826ACF1E1BF1BEB000B5FC5D /* Twitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF1D1BF1BEB000B5FC5D /* Twitter.swift */; };
+ 826ACF201BF1BEB800B5FC5D /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF1F1BF1BEB800B5FC5D /* Settings.swift */; };
+ 826ACF221BF1BEBF00B5FC5D /* AppStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826ACF211BF1BEBF00B5FC5D /* AppStore.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 826ACEEA1BF1B10A00B5FC5D /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 826ACED51BF1B10A00B5FC5D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 826ACEDD1BF1B10A00B5FC5D;
+ remoteInfo = Appz;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 826ACEDE1BF1B10A00B5FC5D /* Appz.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Appz.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 826ACEE11BF1B10A00B5FC5D /* Appz.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Appz.h; sourceTree = "<group>"; };
+ 826ACEE31BF1B10A00B5FC5D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 826ACEE81BF1B10A00B5FC5D /* AppzTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AppzTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 826ACEED1BF1B10A00B5FC5D /* AppzTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppzTests.swift; sourceTree = "<group>"; };
+ 826ACEEF1BF1B10A00B5FC5D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 826ACF181BF1BD1F00B5FC5D /* AvailableApplications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvailableApplications.swift; sourceTree = "<group>"; };
+ 826ACF1A1BF1BD7F00B5FC5D /* ApplicationAccess.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationAccess.swift; sourceTree = "<group>"; };
+ 826ACF1D1BF1BEB000B5FC5D /* Twitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Twitter.swift; sourceTree = "<group>"; };
+ 826ACF1F1BF1BEB800B5FC5D /* Settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
+ 826ACF211BF1BEBF00B5FC5D /* AppStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppStore.swift; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 826ACEDA1BF1B10A00B5FC5D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 826ACEE51BF1B10A00B5FC5D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 826ACEE91BF1B10A00B5FC5D /* Appz.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 826ACED41BF1B10A00B5FC5D = {
+ isa = PBXGroup;
+ children = (
+ 826ACEE01BF1B10A00B5FC5D /* Appz */,
+ 826ACEEC1BF1B10A00B5FC5D /* AppzTests */,
+ 826ACEDF1BF1B10A00B5FC5D /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ 826ACEDF1BF1B10A00B5FC5D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 826ACEDE1BF1B10A00B5FC5D /* Appz.framework */,
+ 826ACEE81BF1B10A00B5FC5D /* AppzTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 826ACEE01BF1B10A00B5FC5D /* Appz */ = {
+ isa = PBXGroup;
+ children = (
+ 826ACF1C1BF1BE9C00B5FC5D /* Apps */,
+ 826ACF171BF1BCF500B5FC5D /* Entity */,
+ 826ACEE11BF1B10A00B5FC5D /* Appz.h */,
+ 826ACEE31BF1B10A00B5FC5D /* Info.plist */,
+ );
+ path = Appz;
+ sourceTree = "<group>";
+ };
+ 826ACEEC1BF1B10A00B5FC5D /* AppzTests */ = {
+ isa = PBXGroup;
+ children = (
+ 826ACEED1BF1B10A00B5FC5D /* AppzTests.swift */,
+ 826ACEEF1BF1B10A00B5FC5D /* Info.plist */,
+ );
+ path = AppzTests;
+ sourceTree = "<group>";
+ };
+ 826ACF171BF1BCF500B5FC5D /* Entity */ = {
+ isa = PBXGroup;
+ children = (
+ 826ACF181BF1BD1F00B5FC5D /* AvailableApplications.swift */,
+ 826ACF1A1BF1BD7F00B5FC5D /* ApplicationAccess.swift */,
+ );
+ path = Entity;
+ sourceTree = "<group>";
+ };
+ 826ACF1C1BF1BE9C00B5FC5D /* Apps */ = {
+ isa = PBXGroup;
+ children = (
+ 826ACF1D1BF1BEB000B5FC5D /* Twitter.swift */,
+ 826ACF1F1BF1BEB800B5FC5D /* Settings.swift */,
+ 826ACF211BF1BEBF00B5FC5D /* AppStore.swift */,
+ );
+ path = Apps;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 826ACEDB1BF1B10A00B5FC5D /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 826ACEE21BF1B10A00B5FC5D /* Appz.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 826ACEDD1BF1B10A00B5FC5D /* Appz */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 826ACEF21BF1B10A00B5FC5D /* Build configuration list for PBXNativeTarget "Appz" */;
+ buildPhases = (
+ 826ACED91BF1B10A00B5FC5D /* Sources */,
+ 826ACEDA1BF1B10A00B5FC5D /* Frameworks */,
+ 826ACEDB1BF1B10A00B5FC5D /* Headers */,
+ 826ACEDC1BF1B10A00B5FC5D /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Appz;
+ productName = Appz;
+ productReference = 826ACEDE1BF1B10A00B5FC5D /* Appz.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+ 826ACEE71BF1B10A00B5FC5D /* AppzTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 826ACEF51BF1B10A00B5FC5D /* Build configuration list for PBXNativeTarget "AppzTests" */;
+ buildPhases = (
+ 826ACEE41BF1B10A00B5FC5D /* Sources */,
+ 826ACEE51BF1B10A00B5FC5D /* Frameworks */,
+ 826ACEE61BF1B10A00B5FC5D /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 826ACEEB1BF1B10A00B5FC5D /* PBXTargetDependency */,
+ );
+ name = AppzTests;
+ productName = AppzTests;
+ productReference = 826ACEE81BF1B10A00B5FC5D /* AppzTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 826ACED51BF1B10A00B5FC5D /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastSwiftUpdateCheck = 0710;
+ LastUpgradeCheck = 0710;
+ ORGANIZATIONNAME = kitz;
+ TargetAttributes = {
+ 826ACEDD1BF1B10A00B5FC5D = {
+ CreatedOnToolsVersion = 7.1;
+ };
+ 826ACEE71BF1B10A00B5FC5D = {
+ CreatedOnToolsVersion = 7.1;
+ };
+ };
+ };
+ buildConfigurationList = 826ACED81BF1B10A00B5FC5D /* Build configuration list for PBXProject "Appz" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 826ACED41BF1B10A00B5FC5D;
+ productRefGroup = 826ACEDF1BF1B10A00B5FC5D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 826ACEDD1BF1B10A00B5FC5D /* Appz */,
+ 826ACEE71BF1B10A00B5FC5D /* AppzTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 826ACEDC1BF1B10A00B5FC5D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 826ACEE61BF1B10A00B5FC5D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 826ACED91BF1B10A00B5FC5D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 826ACF1B1BF1BD7F00B5FC5D /* ApplicationAccess.swift in Sources */,
+ 826ACF221BF1BEBF00B5FC5D /* AppStore.swift in Sources */,
+ 826ACF1E1BF1BEB000B5FC5D /* Twitter.swift in Sources */,
+ 826ACF201BF1BEB800B5FC5D /* Settings.swift in Sources */,
+ 826ACF191BF1BD1F00B5FC5D /* AvailableApplications.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 826ACEE41BF1B10A00B5FC5D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 826ACEEE1BF1B10A00B5FC5D /* AppzTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 826ACEEB1BF1B10A00B5FC5D /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 826ACEDD1BF1B10A00B5FC5D /* Appz */;
+ targetProxy = 826ACEEA1BF1B10A00B5FC5D /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 826ACEF01BF1B10A00B5FC5D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.1;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Debug;
+ };
+ 826ACEF11BF1B10A00B5FC5D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.1;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Release;
+ };
+ 826ACEF31BF1B10A00B5FC5D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ DEFINES_MODULE = YES;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ INFOPLIST_FILE = Appz/Info.plist;
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = io.kitz.Appz;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ 826ACEF41BF1B10A00B5FC5D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ DEFINES_MODULE = YES;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ INFOPLIST_FILE = Appz/Info.plist;
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = io.kitz.Appz;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ };
+ name = Release;
+ };
+ 826ACEF61BF1B10A00B5FC5D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INFOPLIST_FILE = AppzTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = io.kitz.AppzTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 826ACEF71BF1B10A00B5FC5D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INFOPLIST_FILE = AppzTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = io.kitz.AppzTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 826ACED81BF1B10A00B5FC5D /* Build configuration list for PBXProject "Appz" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 826ACEF01BF1B10A00B5FC5D /* Debug */,
+ 826ACEF11BF1B10A00B5FC5D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 826ACEF21BF1B10A00B5FC5D /* Build configuration list for PBXNativeTarget "Appz" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 826ACEF31BF1B10A00B5FC5D /* Debug */,
+ 826ACEF41BF1B10A00B5FC5D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ };
+ 826ACEF51BF1B10A00B5FC5D /* Build configuration list for PBXNativeTarget "AppzTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 826ACEF61BF1B10A00B5FC5D /* Debug */,
+ 826ACEF71BF1B10A00B5FC5D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 826ACED51BF1B10A00B5FC5D /* Project object */;
+}
4 Playground/Playground.playground/contents.xcplayground
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<playground version='5.0' target-platform='ios' display-mode='raw'>
+ <timeline fileName='timeline.xctimeline'/>
+</playground>
7 Playground/Playground.playground/playground.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:">
+ </FileRef>
+</Workspace>
6 Playground/Playground.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Timeline
+ version = "3.0">
+ <TimelineItems>
+ </TimelineItems>
+</Timeline>
84 README.md
@@ -0,0 +1,84 @@
+
+# Appz
+
+![Version](https://img.shields.io/badge/version-prerelease-orange.svg)
+[![Travis CI](https://travis-ci.org/SwiftKitz/Appz.svg?branch=master)](https://travis-ci.org/SwiftKitz/Appz)
+![Swift](https://img.shields.io/badge/swift-2.1-blue.svg)
+![Platforms](https://img.shields.io/badge/platform-ios-lightgrey.svg)
+
+Deeplinking to external applications made easy!
+
+_Even though I shipped it with my app, I still need to invest the time to set this up, and finalize the API. Contributors welcome!_
+
+## Highlights
+
++ __Cleanly Separates App Specs:__<br />
+It was crucial to make sure the library can scale as the number of supported apps increase. Therefor, each supported app is implemented in isolation in a separate file.
+
++ __Full Autocomplete Support__:
+The API has been carefully designed to make the most out of auto complete features, so you don't have to even peak into any docs nor the code!
+
++ __Full Testing:__<br />
+To make the specs as transparent as possible, the library has tests to make sure every external application action has tests with the expected results.
+
+## Features
+
+You can try them in the playground shipped with the framework!
+
+__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)
+```
+
+__Add your own application:__
+
+```swift
+extension AvailableApplications {
+
+ struct MyApp: ExternalApplication {
+
+ let scheme = "myapp:"
+ let fallbackURL: String? = nil
+ }
+
+ func myApp(action: MyApp.Action) -> Bool {
+ return appCaller.launch(MyApp(), action: action)
+ }
+}
+
+extension AvailableApplications.MyApp {
+
+ enum Action: ExternalApplicationAction {
+
+ case Open
+ }
+}
+
+app.open.myApp(.Open)
+```
+
+__Supported Apps (for now!):__
+
+App | Actions
+----|--------
+AppStore | Developer, App
+AppSettings | Open
+Twitter | Status, UserHandle, UserId, List, Post, Search, Timeline, Mentions, Messages
+
+## Motivation
+
+I've gone through way too much pain than I am willing to admit integrating deeplinking in my app. It is very easy to forget calling `canOpenURL` or missing a colon somewhere. Another pain point was savaging the web for all the different specs for different applications.
+
+With this library, you can keep the external application deep linking spec separately and rest assured as it is open source and maintained by the wonderful github community!
+
+## Author
+
+Mazyod ([@Mazyod](http://twitter.com/mazyod))
+
+## License
+
+Appz is released under the MIT license. See LICENSE for details.

0 comments on commit c1d9904

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