├── .gitignore ├── Design └── VisualPairingHack.sketch ├── LICENSE ├── README.md ├── VisualPairingHack.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ └── VisualPairingHack.xcscheme ├── VisualPairingHack ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-40.png │ │ ├── Icon-40@2x.png │ │ ├── Icon-40@3x.png │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-72.png │ │ ├── Icon-72@2x.png │ │ ├── Icon-76.png │ │ ├── Icon-76@2x.png │ │ ├── Icon-83.5@2x.png │ │ ├── Icon-Small-50.png │ │ ├── Icon-Small-50@2x.png │ │ ├── Icon-Small.png │ │ ├── Icon-Small@2x.png │ │ ├── Icon-Small@3x.png │ │ ├── Icon.png │ │ ├── Icon@2x.png │ │ ├── NotificationIcon@2x.png │ │ ├── NotificationIcon@3x.png │ │ ├── NotificationIcon~ipad.png │ │ ├── NotificationIcon~ipad@2x.png │ │ └── ios-marketing.png │ ├── Contents.json │ ├── generate.imageset │ │ ├── Contents.json │ │ ├── generate.png │ │ ├── generate@2x.png │ │ └── generate@3x.png │ ├── particles.dataset │ │ ├── Contents.json │ │ └── particles.caar │ └── scan.imageset │ │ ├── Contents.json │ │ ├── scan.png │ │ ├── scan@2x.png │ │ └── scan@3x.png ├── Base.lproj │ └── LaunchScreen.storyboard ├── Info.plist ├── MagicCodeViewController.h ├── MagicCodeViewController.m ├── MagicScannerViewController.h ├── MagicScannerViewController.m ├── VisualPairing.h └── main.m └── demo.png /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | __MACOSX 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | *.xcworkspace 12 | !default.xcworkspace 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | DerivedData 17 | .idea/ 18 | Crashlytics.sh 19 | generatechangelog.sh 20 | Pods/ 21 | Carthage 22 | Provisioning 23 | Crashlytics.sh -------------------------------------------------------------------------------- /Design/VisualPairingHack.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/Design/VisualPairingHack.sketch -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Guilherme Rambo 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | - Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | - Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VisualPairingHack 2 | 3 | An experiment with the private VisualPairing framework used for automatic iOS and watchOS device pairing. 4 | 5 | ![demo](./demo.png) -------------------------------------------------------------------------------- /VisualPairingHack.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | DDBAE160222200800049BE94 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DDBAE15F222200800049BE94 /* AppDelegate.m */; }; 11 | DDBAE163222200800049BE94 /* MagicCodeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DDBAE162222200800049BE94 /* MagicCodeViewController.m */; }; 12 | DDBAE168222200830049BE94 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDBAE167222200830049BE94 /* Assets.xcassets */; }; 13 | DDBAE16B222200830049BE94 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DDBAE169222200830049BE94 /* LaunchScreen.storyboard */; }; 14 | DDBAE16E222200830049BE94 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DDBAE16D222200830049BE94 /* main.m */; }; 15 | DDBAE176222205870049BE94 /* MagicScannerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DDBAE175222205870049BE94 /* MagicScannerViewController.m */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | DDBAE15B222200800049BE94 /* VisualPairingHack.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VisualPairingHack.app; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | DDBAE15E222200800049BE94 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 21 | DDBAE15F222200800049BE94 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 22 | DDBAE161222200800049BE94 /* MagicCodeViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MagicCodeViewController.h; sourceTree = ""; }; 23 | DDBAE162222200800049BE94 /* MagicCodeViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MagicCodeViewController.m; sourceTree = ""; }; 24 | DDBAE167222200830049BE94 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 25 | DDBAE16A222200830049BE94 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 26 | DDBAE16C222200830049BE94 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 27 | DDBAE16D222200830049BE94 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 28 | DDBAE174222205870049BE94 /* MagicScannerViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MagicScannerViewController.h; sourceTree = ""; }; 29 | DDBAE175222205870049BE94 /* MagicScannerViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MagicScannerViewController.m; sourceTree = ""; }; 30 | DDBAE177222205A00049BE94 /* VisualPairing.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VisualPairing.h; sourceTree = ""; }; 31 | /* End PBXFileReference section */ 32 | 33 | /* Begin PBXFrameworksBuildPhase section */ 34 | DDBAE158222200800049BE94 /* Frameworks */ = { 35 | isa = PBXFrameworksBuildPhase; 36 | buildActionMask = 2147483647; 37 | files = ( 38 | ); 39 | runOnlyForDeploymentPostprocessing = 0; 40 | }; 41 | /* End PBXFrameworksBuildPhase section */ 42 | 43 | /* Begin PBXGroup section */ 44 | DDBAE152222200800049BE94 = { 45 | isa = PBXGroup; 46 | children = ( 47 | DDBAE15D222200800049BE94 /* VisualPairingHack */, 48 | DDBAE15C222200800049BE94 /* Products */, 49 | ); 50 | sourceTree = ""; 51 | }; 52 | DDBAE15C222200800049BE94 /* Products */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | DDBAE15B222200800049BE94 /* VisualPairingHack.app */, 56 | ); 57 | name = Products; 58 | sourceTree = ""; 59 | }; 60 | DDBAE15D222200800049BE94 /* VisualPairingHack */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | DDBAE177222205A00049BE94 /* VisualPairing.h */, 64 | DDBAE15E222200800049BE94 /* AppDelegate.h */, 65 | DDBAE15F222200800049BE94 /* AppDelegate.m */, 66 | DDBAE161222200800049BE94 /* MagicCodeViewController.h */, 67 | DDBAE162222200800049BE94 /* MagicCodeViewController.m */, 68 | DDBAE174222205870049BE94 /* MagicScannerViewController.h */, 69 | DDBAE175222205870049BE94 /* MagicScannerViewController.m */, 70 | DDBAE167222200830049BE94 /* Assets.xcassets */, 71 | DDBAE169222200830049BE94 /* LaunchScreen.storyboard */, 72 | DDBAE16C222200830049BE94 /* Info.plist */, 73 | DDBAE16D222200830049BE94 /* main.m */, 74 | ); 75 | path = VisualPairingHack; 76 | sourceTree = ""; 77 | }; 78 | /* End PBXGroup section */ 79 | 80 | /* Begin PBXNativeTarget section */ 81 | DDBAE15A222200800049BE94 /* VisualPairingHack */ = { 82 | isa = PBXNativeTarget; 83 | buildConfigurationList = DDBAE171222200830049BE94 /* Build configuration list for PBXNativeTarget "VisualPairingHack" */; 84 | buildPhases = ( 85 | DDBAE157222200800049BE94 /* Sources */, 86 | DDBAE158222200800049BE94 /* Frameworks */, 87 | DDBAE159222200800049BE94 /* Resources */, 88 | ); 89 | buildRules = ( 90 | ); 91 | dependencies = ( 92 | ); 93 | name = VisualPairingHack; 94 | productName = VisualPairingHack; 95 | productReference = DDBAE15B222200800049BE94 /* VisualPairingHack.app */; 96 | productType = "com.apple.product-type.application"; 97 | }; 98 | /* End PBXNativeTarget section */ 99 | 100 | /* Begin PBXProject section */ 101 | DDBAE153222200800049BE94 /* Project object */ = { 102 | isa = PBXProject; 103 | attributes = { 104 | LastUpgradeCheck = 1020; 105 | ORGANIZATIONNAME = "Guilherme Rambo"; 106 | TargetAttributes = { 107 | DDBAE15A222200800049BE94 = { 108 | CreatedOnToolsVersion = 10.2; 109 | }; 110 | }; 111 | }; 112 | buildConfigurationList = DDBAE156222200800049BE94 /* Build configuration list for PBXProject "VisualPairingHack" */; 113 | compatibilityVersion = "Xcode 9.3"; 114 | developmentRegion = en; 115 | hasScannedForEncodings = 0; 116 | knownRegions = ( 117 | en, 118 | Base, 119 | ); 120 | mainGroup = DDBAE152222200800049BE94; 121 | productRefGroup = DDBAE15C222200800049BE94 /* Products */; 122 | projectDirPath = ""; 123 | projectRoot = ""; 124 | targets = ( 125 | DDBAE15A222200800049BE94 /* VisualPairingHack */, 126 | ); 127 | }; 128 | /* End PBXProject section */ 129 | 130 | /* Begin PBXResourcesBuildPhase section */ 131 | DDBAE159222200800049BE94 /* Resources */ = { 132 | isa = PBXResourcesBuildPhase; 133 | buildActionMask = 2147483647; 134 | files = ( 135 | DDBAE16B222200830049BE94 /* LaunchScreen.storyboard in Resources */, 136 | DDBAE168222200830049BE94 /* Assets.xcassets in Resources */, 137 | ); 138 | runOnlyForDeploymentPostprocessing = 0; 139 | }; 140 | /* End PBXResourcesBuildPhase section */ 141 | 142 | /* Begin PBXSourcesBuildPhase section */ 143 | DDBAE157222200800049BE94 /* Sources */ = { 144 | isa = PBXSourcesBuildPhase; 145 | buildActionMask = 2147483647; 146 | files = ( 147 | DDBAE163222200800049BE94 /* MagicCodeViewController.m in Sources */, 148 | DDBAE176222205870049BE94 /* MagicScannerViewController.m in Sources */, 149 | DDBAE16E222200830049BE94 /* main.m in Sources */, 150 | DDBAE160222200800049BE94 /* AppDelegate.m in Sources */, 151 | ); 152 | runOnlyForDeploymentPostprocessing = 0; 153 | }; 154 | /* End PBXSourcesBuildPhase section */ 155 | 156 | /* Begin PBXVariantGroup section */ 157 | DDBAE169222200830049BE94 /* LaunchScreen.storyboard */ = { 158 | isa = PBXVariantGroup; 159 | children = ( 160 | DDBAE16A222200830049BE94 /* Base */, 161 | ); 162 | name = LaunchScreen.storyboard; 163 | sourceTree = ""; 164 | }; 165 | /* End PBXVariantGroup section */ 166 | 167 | /* Begin XCBuildConfiguration section */ 168 | DDBAE16F222200830049BE94 /* Debug */ = { 169 | isa = XCBuildConfiguration; 170 | buildSettings = { 171 | ALWAYS_SEARCH_USER_PATHS = NO; 172 | CLANG_ANALYZER_NONNULL = YES; 173 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 174 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 175 | CLANG_CXX_LIBRARY = "libc++"; 176 | CLANG_ENABLE_MODULES = YES; 177 | CLANG_ENABLE_OBJC_ARC = YES; 178 | CLANG_ENABLE_OBJC_WEAK = YES; 179 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 180 | CLANG_WARN_BOOL_CONVERSION = YES; 181 | CLANG_WARN_COMMA = YES; 182 | CLANG_WARN_CONSTANT_CONVERSION = YES; 183 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 184 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 185 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 186 | CLANG_WARN_EMPTY_BODY = YES; 187 | CLANG_WARN_ENUM_CONVERSION = YES; 188 | CLANG_WARN_INFINITE_RECURSION = YES; 189 | CLANG_WARN_INT_CONVERSION = YES; 190 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 191 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 192 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 193 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 194 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 195 | CLANG_WARN_STRICT_PROTOTYPES = YES; 196 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 197 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 198 | CLANG_WARN_UNREACHABLE_CODE = YES; 199 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 200 | CODE_SIGN_IDENTITY = "iPhone Developer"; 201 | COPY_PHASE_STRIP = NO; 202 | DEBUG_INFORMATION_FORMAT = dwarf; 203 | ENABLE_STRICT_OBJC_MSGSEND = YES; 204 | ENABLE_TESTABILITY = YES; 205 | GCC_C_LANGUAGE_STANDARD = gnu11; 206 | GCC_DYNAMIC_NO_PIC = NO; 207 | GCC_NO_COMMON_BLOCKS = YES; 208 | GCC_OPTIMIZATION_LEVEL = 0; 209 | GCC_PREPROCESSOR_DEFINITIONS = ( 210 | "DEBUG=1", 211 | "$(inherited)", 212 | ); 213 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 214 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 215 | GCC_WARN_UNDECLARED_SELECTOR = YES; 216 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 217 | GCC_WARN_UNUSED_FUNCTION = YES; 218 | GCC_WARN_UNUSED_VARIABLE = YES; 219 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 220 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 221 | MTL_FAST_MATH = YES; 222 | ONLY_ACTIVE_ARCH = YES; 223 | SDKROOT = iphoneos; 224 | }; 225 | name = Debug; 226 | }; 227 | DDBAE170222200830049BE94 /* Release */ = { 228 | isa = XCBuildConfiguration; 229 | buildSettings = { 230 | ALWAYS_SEARCH_USER_PATHS = NO; 231 | CLANG_ANALYZER_NONNULL = YES; 232 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 233 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 234 | CLANG_CXX_LIBRARY = "libc++"; 235 | CLANG_ENABLE_MODULES = YES; 236 | CLANG_ENABLE_OBJC_ARC = YES; 237 | CLANG_ENABLE_OBJC_WEAK = YES; 238 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 239 | CLANG_WARN_BOOL_CONVERSION = YES; 240 | CLANG_WARN_COMMA = YES; 241 | CLANG_WARN_CONSTANT_CONVERSION = YES; 242 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 243 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 244 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 245 | CLANG_WARN_EMPTY_BODY = YES; 246 | CLANG_WARN_ENUM_CONVERSION = YES; 247 | CLANG_WARN_INFINITE_RECURSION = YES; 248 | CLANG_WARN_INT_CONVERSION = YES; 249 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 250 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 251 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 252 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 253 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 254 | CLANG_WARN_STRICT_PROTOTYPES = YES; 255 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 256 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 257 | CLANG_WARN_UNREACHABLE_CODE = YES; 258 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 259 | CODE_SIGN_IDENTITY = "iPhone Developer"; 260 | COPY_PHASE_STRIP = NO; 261 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 262 | ENABLE_NS_ASSERTIONS = NO; 263 | ENABLE_STRICT_OBJC_MSGSEND = YES; 264 | GCC_C_LANGUAGE_STANDARD = gnu11; 265 | GCC_NO_COMMON_BLOCKS = YES; 266 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 267 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 268 | GCC_WARN_UNDECLARED_SELECTOR = YES; 269 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 270 | GCC_WARN_UNUSED_FUNCTION = YES; 271 | GCC_WARN_UNUSED_VARIABLE = YES; 272 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 273 | MTL_ENABLE_DEBUG_INFO = NO; 274 | MTL_FAST_MATH = YES; 275 | SDKROOT = iphoneos; 276 | VALIDATE_PRODUCT = YES; 277 | }; 278 | name = Release; 279 | }; 280 | DDBAE172222200830049BE94 /* Debug */ = { 281 | isa = XCBuildConfiguration; 282 | buildSettings = { 283 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 284 | CODE_SIGN_STYLE = Automatic; 285 | DEVELOPMENT_TEAM = 8C7439RJLG; 286 | INFOPLIST_FILE = VisualPairingHack/Info.plist; 287 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 288 | LD_RUNPATH_SEARCH_PATHS = ( 289 | "$(inherited)", 290 | "@executable_path/Frameworks", 291 | ); 292 | PRODUCT_BUNDLE_IDENTIFIER = codes.rambo.VisualPairingHack; 293 | PRODUCT_NAME = "$(TARGET_NAME)"; 294 | TARGETED_DEVICE_FAMILY = "1,2"; 295 | }; 296 | name = Debug; 297 | }; 298 | DDBAE173222200830049BE94 /* Release */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 302 | CODE_SIGN_STYLE = Automatic; 303 | DEVELOPMENT_TEAM = 8C7439RJLG; 304 | INFOPLIST_FILE = VisualPairingHack/Info.plist; 305 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 306 | LD_RUNPATH_SEARCH_PATHS = ( 307 | "$(inherited)", 308 | "@executable_path/Frameworks", 309 | ); 310 | PRODUCT_BUNDLE_IDENTIFIER = codes.rambo.VisualPairingHack; 311 | PRODUCT_NAME = "$(TARGET_NAME)"; 312 | TARGETED_DEVICE_FAMILY = "1,2"; 313 | }; 314 | name = Release; 315 | }; 316 | /* End XCBuildConfiguration section */ 317 | 318 | /* Begin XCConfigurationList section */ 319 | DDBAE156222200800049BE94 /* Build configuration list for PBXProject "VisualPairingHack" */ = { 320 | isa = XCConfigurationList; 321 | buildConfigurations = ( 322 | DDBAE16F222200830049BE94 /* Debug */, 323 | DDBAE170222200830049BE94 /* Release */, 324 | ); 325 | defaultConfigurationIsVisible = 0; 326 | defaultConfigurationName = Release; 327 | }; 328 | DDBAE171222200830049BE94 /* Build configuration list for PBXNativeTarget "VisualPairingHack" */ = { 329 | isa = XCConfigurationList; 330 | buildConfigurations = ( 331 | DDBAE172222200830049BE94 /* Debug */, 332 | DDBAE173222200830049BE94 /* Release */, 333 | ); 334 | defaultConfigurationIsVisible = 0; 335 | defaultConfigurationName = Release; 336 | }; 337 | /* End XCConfigurationList section */ 338 | }; 339 | rootObject = DDBAE153222200800049BE94 /* Project object */; 340 | } 341 | -------------------------------------------------------------------------------- /VisualPairingHack.xcodeproj/xcshareddata/xcschemes/VisualPairingHack.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /VisualPairingHack/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // VisualPairingHack 4 | // 5 | // Created by Guilherme Rambo on 23/02/19. 6 | // Copyright © 2019 Guilherme Rambo. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /VisualPairingHack/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // VisualPairingHack 4 | // 5 | // Created by Guilherme Rambo on 23/02/19. 6 | // Copyright © 2019 Guilherme Rambo. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | #import "MagicCodeViewController.h" 12 | #import "MagicScannerViewController.h" 13 | 14 | @interface AppDelegate () 15 | 16 | @property (nonatomic, strong) UITabBarController *tabController; 17 | 18 | @end 19 | 20 | @implementation AppDelegate 21 | 22 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 23 | BOOL result = [[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/VisualPairing.framework"] load]; 24 | assert(result); 25 | 26 | self.window = [UIWindow new]; 27 | 28 | MagicCodeViewController *codeController = [MagicCodeViewController new]; 29 | MagicScannerViewController *scannerController = [MagicScannerViewController new]; 30 | 31 | self.tabController = [UITabBarController new]; 32 | 33 | self.tabController.viewControllers = @[codeController, scannerController]; 34 | 35 | self.window.rootViewController = self.tabController; 36 | 37 | [self.window makeKeyAndVisible]; 38 | 39 | return YES; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "ipad", 5 | "size" : "40x40", 6 | "scale" : "1x", 7 | "filename" : "Icon-40.png" 8 | }, 9 | { 10 | "idiom" : "ipad", 11 | "size" : "40x40", 12 | "scale" : "2x", 13 | "filename" : "Icon-40@2x.png" 14 | }, 15 | { 16 | "idiom" : "iphone", 17 | "size" : "60x60", 18 | "scale" : "2x", 19 | "filename" : "Icon-60@2x.png" 20 | }, 21 | { 22 | "idiom" : "ipad", 23 | "size" : "72x72", 24 | "scale" : "1x", 25 | "filename" : "Icon-72.png" 26 | }, 27 | { 28 | "idiom" : "ipad", 29 | "size" : "72x72", 30 | "scale" : "2x", 31 | "filename" : "Icon-72@2x.png" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "76x76", 36 | "scale" : "1x", 37 | "filename" : "Icon-76.png" 38 | }, 39 | { 40 | "idiom" : "ipad", 41 | "size" : "76x76", 42 | "scale" : "2x", 43 | "filename" : "Icon-76@2x.png" 44 | }, 45 | { 46 | "idiom" : "ipad", 47 | "size" : "50x50", 48 | "scale" : "1x", 49 | "filename" : "Icon-Small-50.png" 50 | }, 51 | { 52 | "idiom" : "ipad", 53 | "size" : "50x50", 54 | "scale" : "2x", 55 | "filename" : "Icon-Small-50@2x.png" 56 | }, 57 | { 58 | "idiom" : "iphone", 59 | "size" : "29x29", 60 | "scale" : "1x", 61 | "filename" : "Icon-Small.png" 62 | }, 63 | { 64 | "idiom" : "iphone", 65 | "size" : "29x29", 66 | "scale" : "2x", 67 | "filename" : "Icon-Small@2x.png" 68 | }, 69 | { 70 | "idiom" : "iphone", 71 | "size" : "57x57", 72 | "scale" : "1x", 73 | "filename" : "Icon.png" 74 | }, 75 | { 76 | "idiom" : "iphone", 77 | "size" : "57x57", 78 | "scale" : "2x", 79 | "filename" : "Icon@2x.png" 80 | }, 81 | { 82 | "idiom" : "iphone", 83 | "size" : "29x29", 84 | "scale" : "3x", 85 | "filename" : "Icon-Small@3x.png" 86 | }, 87 | { 88 | "idiom" : "iphone", 89 | "size" : "40x40", 90 | "scale" : "3x", 91 | "filename" : "Icon-40@3x.png" 92 | }, 93 | { 94 | "idiom" : "iphone", 95 | "size" : "60x60", 96 | "scale" : "3x", 97 | "filename" : "Icon-60@3x.png" 98 | }, 99 | { 100 | "idiom" : "iphone", 101 | "size" : "40x40", 102 | "scale" : "2x", 103 | "filename" : "Icon-40@2x.png" 104 | }, 105 | { 106 | "idiom" : "ipad", 107 | "size" : "29x29", 108 | "scale" : "1x", 109 | "filename" : "Icon-Small.png" 110 | }, 111 | { 112 | "idiom" : "ipad", 113 | "size" : "29x29", 114 | "scale" : "2x", 115 | "filename" : "Icon-Small@2x.png" 116 | }, 117 | { 118 | "idiom" : "ipad", 119 | "size" : "83.5x83.5", 120 | "scale" : "2x", 121 | "filename" : "Icon-83.5@2x.png" 122 | }, 123 | { 124 | "idiom" : "iphone", 125 | "size" : "20x20", 126 | "scale" : "2x", 127 | "filename" : "NotificationIcon@2x.png" 128 | }, 129 | { 130 | "idiom" : "iphone", 131 | "size" : "20x20", 132 | "scale" : "3x", 133 | "filename" : "NotificationIcon@3x.png" 134 | }, 135 | { 136 | "idiom" : "ipad", 137 | "size" : "20x20", 138 | "scale" : "1x", 139 | "filename" : "NotificationIcon~ipad.png" 140 | }, 141 | { 142 | "idiom" : "ipad", 143 | "size" : "20x20", 144 | "scale" : "2x", 145 | "filename" : "NotificationIcon~ipad@2x.png" 146 | }, 147 | { 148 | "idiom" : "ios-marketing", 149 | "size" : "1024x1024", 150 | "scale" : "1x", 151 | "filename" : "ios-marketing.png" 152 | } 153 | ], 154 | "info" : { 155 | "author" : "xcode", 156 | "version" : 1 157 | } 158 | } -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-40.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-72.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/Icon@2x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/NotificationIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/NotificationIcon@2x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/NotificationIcon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/NotificationIcon@3x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad@2x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/AppIcon.appiconset/ios-marketing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/AppIcon.appiconset/ios-marketing.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/generate.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "generate.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "generate@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "generate@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/generate.imageset/generate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/generate.imageset/generate.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/generate.imageset/generate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/generate.imageset/generate@2x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/generate.imageset/generate@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/generate.imageset/generate@3x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/particles.dataset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "data" : [ 7 | { 8 | "idiom" : "universal", 9 | "filename" : "particles.caar" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/particles.dataset/particles.caar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/particles.dataset/particles.caar -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/scan.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "scan.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "scan@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "scan@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/scan.imageset/scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/scan.imageset/scan.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/scan.imageset/scan@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/scan.imageset/scan@2x.png -------------------------------------------------------------------------------- /VisualPairingHack/Assets.xcassets/scan.imageset/scan@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/VisualPairingHack/Assets.xcassets/scan.imageset/scan@3x.png -------------------------------------------------------------------------------- /VisualPairingHack/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /VisualPairingHack/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSCameraUsageDescription 24 | Scan magic code 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UIStatusBarStyle 32 | UIStatusBarStyleLightContent 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /VisualPairingHack/MagicCodeViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MagicCodeViewController.h 3 | // VisualPairingHack 4 | // 5 | // Created by Guilherme Rambo on 23/02/19. 6 | // Copyright © 2019 Guilherme Rambo. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface MagicCodeViewController : UIViewController 12 | 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /VisualPairingHack/MagicCodeViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MagicCodeViewController.m 3 | // VisualPairingHack 4 | // 5 | // Created by Guilherme Rambo on 23/02/19. 6 | // Copyright © 2019 Guilherme Rambo. All rights reserved. 7 | // 8 | 9 | #import "MagicCodeViewController.h" 10 | 11 | #import "VisualPairing.h" 12 | 13 | @interface MagicCodeViewController () 14 | 15 | @property (nonatomic, strong) UIView *codeContainer; 16 | @property (nonatomic, strong) VPPresenterView *codeView; 17 | 18 | @property (nonatomic, strong) UITextField *textField; 19 | 20 | @end 21 | 22 | @implementation MagicCodeViewController 23 | 24 | - (instancetype)init 25 | { 26 | self = [super init]; 27 | 28 | self.title = @"Generate"; 29 | self.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Generate" image:[UIImage imageNamed:@"generate"] tag:0]; 30 | 31 | return self; 32 | } 33 | 34 | - (void)loadView 35 | { 36 | self.view = [UIView new]; 37 | self.view.backgroundColor = [UIColor whiteColor]; 38 | } 39 | 40 | - (void)viewDidLoad { 41 | [super viewDidLoad]; 42 | 43 | [self _configureAsPresenter]; 44 | } 45 | 46 | - (void)_configureAsPresenter 47 | { 48 | CGFloat codeSize = 300; 49 | 50 | self.codeContainer = [UIView new]; 51 | 52 | self.codeContainer.translatesAutoresizingMaskIntoConstraints = NO; 53 | self.codeContainer.clipsToBounds = YES; 54 | 55 | self.codeContainer.backgroundColor = [UIColor whiteColor]; 56 | self.codeContainer.layer.cornerRadius = codeSize/2; 57 | self.codeContainer.layer.borderColor = [UIColor colorWithRed:0.00 green:0.49 blue:1.00 alpha:1.00].CGColor; 58 | self.codeContainer.layer.borderWidth = 1; 59 | 60 | [self.view addSubview:self.codeContainer]; 61 | 62 | [self.codeContainer.widthAnchor constraintEqualToConstant:codeSize].active = YES; 63 | [self.codeContainer.heightAnchor constraintEqualToConstant:codeSize].active = YES; 64 | [self.codeContainer.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES; 65 | [self.codeContainer.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = YES; 66 | 67 | [self _installParticles]; 68 | 69 | self.codeView = [[NSClassFromString(@"VPPresenterView") alloc] initWithFrame:CGRectZero]; 70 | self.codeView.translatesAutoresizingMaskIntoConstraints = NO; 71 | 72 | [self.codeContainer addSubview:self.codeView]; 73 | 74 | [self.codeView.widthAnchor constraintEqualToAnchor:self.codeContainer.widthAnchor].active = YES; 75 | [self.codeView.heightAnchor constraintEqualToAnchor:self.codeContainer.heightAnchor].active = YES; 76 | [self.codeView.centerXAnchor constraintEqualToAnchor:self.codeContainer.centerXAnchor].active = YES; 77 | [self.codeView.centerYAnchor constraintEqualToAnchor:self.codeContainer.centerYAnchor].active = YES; 78 | 79 | [self.codeView setVerificationCode:@"Hello, world"]; 80 | 81 | [self _installCodeField]; 82 | } 83 | 84 | - (void)_installParticles 85 | { 86 | NSData *assetData = [[NSDataAsset alloc] initWithName:@"particles"].data; 87 | if (!assetData) return; 88 | 89 | NSDictionary *caar = [NSKeyedUnarchiver unarchiveObjectWithData:assetData]; 90 | CALayer *rootLayer = caar[@"rootLayer"]; 91 | if (!rootLayer) return; 92 | 93 | [self.codeContainer.layer addSublayer:rootLayer]; 94 | } 95 | 96 | - (void)_installCodeField 97 | { 98 | self.textField = [UITextField new]; 99 | self.textField.delegate = self; 100 | self.textField.text = @"Hello, world"; 101 | self.textField.placeholder = @"Enter code to transmit"; 102 | self.textField.borderStyle = UITextBorderStyleRoundedRect; 103 | 104 | self.textField.translatesAutoresizingMaskIntoConstraints = NO; 105 | 106 | [self.view addSubview:self.textField]; 107 | 108 | [self.textField.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:16].active = YES; 109 | [self.textField.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-16].active = YES; 110 | [self.textField.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:16].active = YES; 111 | } 112 | 113 | - (void)viewDidAppear:(BOOL)animated 114 | { 115 | [super viewDidAppear:animated]; 116 | 117 | [self.codeView start]; 118 | } 119 | 120 | - (BOOL)textFieldShouldReturn:(UITextField *)textField 121 | { 122 | [self.codeView stop]; 123 | 124 | self.codeView.verificationCode = textField.text; 125 | 126 | [self.codeView start]; 127 | 128 | [self.textField resignFirstResponder]; 129 | 130 | return YES; 131 | } 132 | 133 | @end 134 | -------------------------------------------------------------------------------- /VisualPairingHack/MagicScannerViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MagicScannerViewController.h 3 | // VisualPairingHack 4 | // 5 | // Created by Guilherme Rambo on 23/02/19. 6 | // Copyright © 2019 Guilherme Rambo. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface MagicScannerViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /VisualPairingHack/MagicScannerViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MagicScannerViewController.m 3 | // VisualPairingHack 4 | // 5 | // Created by Guilherme Rambo on 23/02/19. 6 | // Copyright © 2019 Guilherme Rambo. All rights reserved. 7 | // 8 | 9 | #import "MagicScannerViewController.h" 10 | 11 | #import "VisualPairing.h" 12 | 13 | @interface MagicScannerViewController () 14 | 15 | @property (nonatomic, strong) VPScannerViewController *scannerController; 16 | @property (nonatomic, strong) UINotificationFeedbackGenerator *feedback; 17 | @property (nonatomic, strong) UILabel *resultLabel; 18 | 19 | @end 20 | 21 | @implementation MagicScannerViewController 22 | 23 | - (instancetype)init 24 | { 25 | self = [super init]; 26 | 27 | self.title = @"Scan"; 28 | self.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Scan" image:[UIImage imageNamed:@"scan"] tag:1]; 29 | 30 | return self; 31 | } 32 | 33 | - (void)loadView 34 | { 35 | self.view = [UIView new]; 36 | self.view.backgroundColor = [UIColor whiteColor]; 37 | } 38 | 39 | - (void)viewDidLoad { 40 | [super viewDidLoad]; 41 | 42 | [self _configureAsScanner]; 43 | } 44 | 45 | - (void)_configureAsScanner 46 | { 47 | self.feedback = [UINotificationFeedbackGenerator new]; 48 | 49 | self.scannerController = [NSClassFromString(@"VPScannerViewController") instantiateViewController]; 50 | self.scannerController.titleMessage = @"Hold the device that's generating the code up to the camera."; 51 | self.scannerController.view.translatesAutoresizingMaskIntoConstraints = NO; 52 | 53 | [self.view addSubview:self.scannerController.view]; 54 | 55 | [self.scannerController.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; 56 | [self.scannerController.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; 57 | [self.scannerController.view.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; 58 | [self.scannerController.view.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor].active = YES; 59 | 60 | __weak typeof(self) weakSelf = self; 61 | self.scannerController.scannedCodeHandler = ^(NSString *code) { 62 | NSLog(@"SCANNED: %@", code); 63 | 64 | dispatch_async(dispatch_get_main_queue(), ^{ 65 | [weakSelf _didScanCode:code]; 66 | }); 67 | }; 68 | 69 | [self addChildViewController:self.scannerController]; 70 | [self.scannerController didMoveToParentViewController:self]; 71 | 72 | [self _installResultLabel]; 73 | } 74 | 75 | - (void)_installResultLabel 76 | { 77 | self.resultLabel = [UILabel new]; 78 | self.resultLabel.translatesAutoresizingMaskIntoConstraints = NO; 79 | self.resultLabel.numberOfLines = 0; 80 | self.resultLabel.lineBreakMode = NSLineBreakByWordWrapping; 81 | self.resultLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium]; 82 | self.resultLabel.textColor = [UIColor blackColor]; 83 | self.resultLabel.textAlignment = NSTextAlignmentCenter; 84 | [self.view addSubview:self.resultLabel]; 85 | self.resultLabel.text = @"Waiting for scan..."; 86 | 87 | [self.resultLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:16].active = YES; 88 | [self.resultLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-16].active = YES; 89 | [self.resultLabel.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:16].active = YES; 90 | } 91 | 92 | - (void)_didScanCode:(NSString *)code 93 | { 94 | if ([code isEqualToString:self.resultLabel.text]) return; 95 | 96 | [self.feedback notificationOccurred:UINotificationFeedbackTypeSuccess]; 97 | self.resultLabel.text = code; 98 | } 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /VisualPairingHack/VisualPairing.h: -------------------------------------------------------------------------------- 1 | // 2 | // VisualPairing.h 3 | // VisualPairingHack 4 | // 5 | // Created by Guilherme Rambo on 23/02/19. 6 | // Copyright © 2019 Guilherme Rambo. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface VPScannerViewController : UIViewController 12 | 13 | + (instancetype)instantiateViewController; 14 | 15 | @property(copy, nonatomic) NSString *titleMessage; 16 | @property(copy, nonatomic) void(^scannedCodeHandler)(NSString *); 17 | 18 | @end 19 | 20 | @interface VPPresenterView: UIView 21 | 22 | - (void)start; 23 | - (void)stop; 24 | 25 | @property (nonatomic, copy) NSString *verificationCode; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /VisualPairingHack/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // VisualPairingHack 4 | // 5 | // Created by Guilherme Rambo on 23/02/19. 6 | // Copyright © 2019 Guilherme Rambo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidegui/VisualPairingHack/50108e41feeab179b1c1f6cb38de1432d0075d94/demo.png --------------------------------------------------------------------------------