├── CHANGELOG.md ├── Assets ├── backbutton.png ├── backbutton@2x.png ├── backbutton@3x.png ├── forwardbutton.png ├── forwardbutton@2x.png └── forwardbutton@3x.png ├── ExampleProject ├── KINWebBrowserExample │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── main.m │ ├── KINWebBrowserExample-Prefix.pch │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── KINAppDelegate.h │ ├── KINWebBrowserExample-Info.plist │ ├── KINWebBrowserExampleViewController.h │ ├── KINWebBrowserExampleViewController.xib │ ├── KINAppDelegate.m │ └── KINWebBrowserExampleViewController.m ├── KINWebBrowserExampleTests │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── KINWebBrowserExampleTests-Info.plist │ └── KINWebBrowserExampleTests.m ├── Podfile ├── KINWebBrowserExample.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── project.pbxproj └── KINWebBrowserExample.xcworkspace │ └── contents.xcworkspacedata ├── .gitignore ├── KINWebBrowser.podspec ├── LICENSE ├── README.md └── KINWebBrowser ├── KINWebBrowserViewController.h └── KINWebBrowserViewController.m /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # KINWebBrowser CHANGELOG 2 | 3 | ## 0.1.0 4 | 5 | Initial release. 6 | -------------------------------------------------------------------------------- /Assets/backbutton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dfmuir/KINWebBrowser/HEAD/Assets/backbutton.png -------------------------------------------------------------------------------- /Assets/backbutton@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dfmuir/KINWebBrowser/HEAD/Assets/backbutton@2x.png -------------------------------------------------------------------------------- /Assets/backbutton@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dfmuir/KINWebBrowser/HEAD/Assets/backbutton@3x.png -------------------------------------------------------------------------------- /Assets/forwardbutton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dfmuir/KINWebBrowser/HEAD/Assets/forwardbutton.png -------------------------------------------------------------------------------- /Assets/forwardbutton@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dfmuir/KINWebBrowser/HEAD/Assets/forwardbutton@2x.png -------------------------------------------------------------------------------- /Assets/forwardbutton@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dfmuir/KINWebBrowser/HEAD/Assets/forwardbutton@3x.png -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExampleTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ExampleProject/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | xcodeproj 'KINWebBrowserExample.xcodeproj' 4 | platform :ios, :deployment_target => '7.0' 5 | 6 | pod 'KINWebBrowser' 7 | 8 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | profile 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | *.hmap 18 | *.xccheckout 19 | 20 | #CocoaPods 21 | Pods 22 | Podfile.lock 23 | Rakefile 24 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // KINWebBrowserExample 4 | // 5 | // Created by David Muir on 2/4/14. 6 | // Copyright (c) 2014 Kinwa, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "KINAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([KINAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample/KINWebBrowserExample-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExampleTests/KINWebBrowserExampleTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.kinwa.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExampleTests/KINWebBrowserExampleTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // KINWebBrowserExampleTests.m 3 | // KINWebBrowserExampleTests 4 | // 5 | // Created by David Muir on 2/4/14. 6 | // Copyright (c) 2014 Kinwa, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface KINWebBrowserExampleTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation KINWebBrowserExampleTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /KINWebBrowser.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | 4 | s.name = "KINWebBrowser" 5 | s.version = "1.3.2" 6 | s.summary = "A web browser module for your apps." 7 | s.description = <<-DESC 8 | KINWebBrowser is a web browser module for your apps. Powered by WKWebView on iOS 8. Backwards compatible with iOS 7 using UIWebView. KINWebBrowser offers the simplest way to add a web browser to your apps. 9 | DESC 10 | 11 | s.homepage = "https://github.com/dfmuir/KINWebBrowser" 12 | s.license = { :type => 'MIT', :file => 'LICENSE' } 13 | s.author = { "David F. Muir V" => "dfmuir@gmail.com" } 14 | s.platform = :ios, '7.0' 15 | s.source = { :git => "https://github.com/dfmuir/KINWebBrowser.git", :tag => s.version.to_s } 16 | s.source_files = 'KINWebBrowser', 'KINWebBrowser/**/*.{h,m}' 17 | s.resources = "Assets/*.png" 18 | s.requires_arc = true 19 | 20 | s.weak_framework = 'WebKit' 21 | 22 | s.dependency 'TUSafariActivity', '1.0.4' 23 | s.dependency 'ARChromeActivity', '1.0.5' 24 | 25 | end 26 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "60x60", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "29x29", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "29x29", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "40x40", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "40x40", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "76x76", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "76x76", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | KINWebBrowser 2 | 3 | Created by David F. Muir V 4 | dfmuir@gmail.com 5 | Co-Founder & Engineer at Kinwa, Inc. 6 | http://www.kinwa.co 7 | 8 | The MIT License (MIT) 9 | 10 | Copyright (c) 2014 David Muir 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy of 13 | this software and associated documentation files (the "Software"), to deal in 14 | the Software without restriction, including without limitation the rights to 15 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 16 | the Software, and to permit persons to whom the Software is furnished to do so, 17 | subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in all 20 | copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 24 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 25 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 26 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "orientation" : "portrait", 20 | "idiom" : "ipad", 21 | "extent" : "full-screen", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "1x" 24 | }, 25 | { 26 | "orientation" : "landscape", 27 | "idiom" : "ipad", 28 | "extent" : "full-screen", 29 | "minimum-system-version" : "7.0", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "full-screen", 36 | "minimum-system-version" : "7.0", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "orientation" : "landscape", 41 | "idiom" : "ipad", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | } 46 | ], 47 | "info" : { 48 | "version" : 1, 49 | "author" : "xcode" 50 | } 51 | } -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample/KINAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // KINAppDelegate.h 3 | // 4 | // KINWebBrowser 5 | // 6 | // Created by David F. Muir V 7 | // dfmuir@gmail.com 8 | // Co-Founder & Engineer at Kinwa, Inc. 9 | // http://www.kinwa.co 10 | // 11 | // The MIT License (MIT) 12 | // 13 | // Copyright (c) 2014 David Muir 14 | // 15 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | // this software and associated documentation files (the "Software"), to deal in 17 | // the Software without restriction, including without limitation the rights to 18 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 19 | // the Software, and to permit persons to whom the Software is furnished to do so, 20 | // subject to the following conditions: 21 | // 22 | // The above copyright notice and this permission notice shall be included in all 23 | // copies or substantial portions of the Software. 24 | // 25 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 27 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 28 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 29 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | // 32 | 33 | 34 | #import 35 | 36 | @interface KINAppDelegate : UIResponder 37 | 38 | @property (strong, nonatomic) UIWindow *window; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample/KINWebBrowserExample-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.kinwa.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample/KINWebBrowserExampleViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // KINWebBrowserExampleViewController.m 3 | // 4 | // KINWebBrowser 5 | // 6 | // Created by David F. Muir V 7 | // dfmuir@gmail.com 8 | // Co-Founder & Engineer at Kinwa, Inc. 9 | // http://www.kinwa.co 10 | // 11 | // The MIT License (MIT) 12 | // 13 | // Copyright (c) 2014 David Muir 14 | // 15 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | // this software and associated documentation files (the "Software"), to deal in 17 | // the Software without restriction, including without limitation the rights to 18 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 19 | // the Software, and to permit persons to whom the Software is furnished to do so, 20 | // subject to the following conditions: 21 | // 22 | // The above copyright notice and this permission notice shall be included in all 23 | // copies or substantial portions of the Software. 24 | // 25 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 27 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 28 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 29 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | // 32 | 33 | 34 | #import 35 | 36 | #import 37 | 38 | @interface KINWebBrowserExampleViewController : UIViewController 39 | 40 | - (IBAction)pushButtonPressed:(id)sender; 41 | - (IBAction)presentButtonPressed:(id)sender; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample/KINWebBrowserExampleViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 28 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample/KINAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // KINAppDelegate.m 3 | // 4 | // KINWebBrowser 5 | // 6 | // Created by David F. Muir V 7 | // dfmuir@gmail.com 8 | // Co-Founder & Engineer at Kinwa, Inc. 9 | // http://www.kinwa.co 10 | // 11 | // The MIT License (MIT) 12 | // 13 | // Copyright (c) 2014 David Muir 14 | // 15 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | // this software and associated documentation files (the "Software"), to deal in 17 | // the Software without restriction, including without limitation the rights to 18 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 19 | // the Software, and to permit persons to whom the Software is furnished to do so, 20 | // subject to the following conditions: 21 | // 22 | // The above copyright notice and this permission notice shall be included in all 23 | // copies or substantial portions of the Software. 24 | // 25 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 27 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 28 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 29 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | // 32 | 33 | 34 | #import "KINAppDelegate.h" 35 | 36 | #import "KINWebBrowserExampleViewController.h" 37 | 38 | @implementation KINAppDelegate 39 | 40 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 41 | { 42 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 43 | // Override point for customization after application launch. 44 | 45 | KINWebBrowserExampleViewController *viewController = [[KINWebBrowserExampleViewController alloc] init]; 46 | 47 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController]; 48 | 49 | [self.window setRootViewController:navigationController]; 50 | self.window.backgroundColor = [UIColor whiteColor]; 51 | [self.window makeKeyAndVisible]; 52 | return YES; 53 | } 54 | 55 | - (void)applicationWillResignActive:(UIApplication *)application 56 | { 57 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 58 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 59 | } 60 | 61 | - (void)applicationDidEnterBackground:(UIApplication *)application 62 | { 63 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 64 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 65 | } 66 | 67 | - (void)applicationWillEnterForeground:(UIApplication *)application 68 | { 69 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 70 | } 71 | 72 | - (void)applicationDidBecomeActive:(UIApplication *)application 73 | { 74 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 75 | } 76 | 77 | - (void)applicationWillTerminate:(UIApplication *)application 78 | { 79 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | KINWebBrowser 2 | ========== 3 | 4 | KINWebBrowser is a web browser module for your apps. 5 | 6 | Powered by [WKWebView](https://developer.apple.com/library/IOs/documentation/WebKit/Reference/WKWebView_Ref/index.html) on iOS 8. Backwards compatible with iOS 7 using [UIWebView](https://developer.apple.com/library/ios/documentation/Uikit/reference/UIWebView_Class/index.html). 7 | 8 | ![KINWebBrowser Screenshots](http://i.imgur.com/z1jkWKG.png) 9 | 10 | Features 11 | ------------------------ 12 | * iOS 7 & 8 support for iPhone and iPad devices 13 | * Safari-like interface 14 | * Animated progress bar 15 | * Customizable UI including tint color 16 | * Portrait and landscape orientation support 17 | * Use with existing UINavigationController or present modally 18 | * Delegate protocol for status callbacks 19 | * Action button to allow users to copy URL, share, or open in Safari & Google Chrome 20 | * Supports subclassing 21 | * Installation with [CocoaPods](http://cocoapods.org/) 22 | 23 | Overview 24 | ------------------------ 25 | KINWebBrowser consists of a single component: 26 | 27 | **`KINWebBrowserViewController`** - a `UIViewController` that contains a full featured web browser. 28 | 29 | *`KINWebBrowserViewController` must be contained in a UINavigationController.* 30 | 31 | **Pushing to the navigation stack:** 32 | ```objective-c 33 | KINWebBrowserViewController *webBrowser = [KINWebBrowserViewController webBrowser]; 34 | [self.navigationController pushViewController:webBrowser animated:YES]; 35 | [webBrowser loadURLString:@"http://www.example.com"]; 36 | ``` 37 | 38 | **Presenting Modally:** 39 | ```objective-c 40 | UINavigationController *webBrowserNavigationController = [KINWebBrowserViewController navigationControllerWithWebBrowser]; 41 | [self presentViewController:webBrowserNavigationController animated:YES completion:nil]; 42 | 43 | KINWebBrowserViewController *webBrowser = [webBrowserNavigationController rootWebBrowser]; 44 | [webBrowser loadURLString:@"http://www.example.com"]; 45 | ``` 46 | 47 | Installation 48 | ------------------------ 49 | 50 | #### CocoaPods 51 | [CocoaPods](http://cocoapods.org) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries in your projects. See the ["Getting Started" for more information](http://guides.cocoapods.org/using/getting-started.html). 52 | 53 | ###### Podfile 54 | 55 | ```ruby 56 | platform :ios, '7.0' 57 | pod 'KINWebBrowser' 58 | ``` 59 | 60 | Dependencies 61 | ------------------------ 62 | These dependency projects should be also installed with KINWebBrowser. They are installed automatically when installing KINWebBrowser with CocoaPods. 63 | 64 | * [TUSafariActivity](https://github.com/davbeck/TUSafariActivity) - a UIActivity subclass that provides an "Open In Safari" action to a UIActivityViewController 65 | * [ARChromeActivity](https://github.com/alextrob/ARChromeActivity) - a UIActivity subclass that provides an "Open In Google Chrome" action to a UIActivityViewController 66 | 67 | 68 | Customizing the User Interface 69 | ------------------------ 70 | 71 | **Tint Color** 72 | 73 | The tint color of the toolbars and toolbar items can be customized. 74 | 75 | ``` 76 | webBrowser.tintColor = [UIColor blueColor]; 77 | webBrowser.barTintColor = [UIColor blackColor]; 78 | ``` 79 | 80 | **Title Bar Content** 81 | 82 | The URL can be shown in the `UINavigationBar` while loading. The title of the page can be shown when loading completes. 83 | ``` 84 | webBrowser.showsURLInNavigationBar = NO; 85 | webBrowser.showsPageTitleInNavigationBar = YES; 86 | ``` 87 | 88 | 89 | Implementing `KINWebBrowserDelegate` Protocol 90 | ------------------------ 91 | `KINWebBrowserDelegate` is a set of `@optional` callback methods to inform the `delegate` of status changes. 92 | 93 | ``` 94 | - (void)webBrowser:(KINWebBrowserViewController *)webBrowser didStartLoadingURL:(NSURL *)URL; 95 | - (void)webBrowser:(KINWebBrowserViewController *)webBrowser didFinishLoadingURL:(NSURL *)URL; 96 | - (void)webBrowser:(KINWebBrowserViewController *)webBrowser didFailToLoadURL:(NSURL *)URL withError:(NSError *)error; 97 | ``` 98 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample/KINWebBrowserExampleViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // KINWebBrowserExampleViewController.m 3 | // 4 | // KINWebBrowser 5 | // 6 | // Created by David F. Muir V 7 | // dfmuir@gmail.com 8 | // Co-Founder & Engineer at Kinwa, Inc. 9 | // http://www.kinwa.co 10 | // 11 | // The MIT License (MIT) 12 | // 13 | // Copyright (c) 2014 David Muir 14 | // 15 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | // this software and associated documentation files (the "Software"), to deal in 17 | // the Software without restriction, including without limitation the rights to 18 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 19 | // the Software, and to permit persons to whom the Software is furnished to do so, 20 | // subject to the following conditions: 21 | // 22 | // The above copyright notice and this permission notice shall be included in all 23 | // copies or substantial portions of the Software. 24 | // 25 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 27 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 28 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 29 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | // 32 | 33 | 34 | #import "KINWebBrowserExampleViewController.h" 35 | 36 | 37 | @interface KINWebBrowserExampleViewController () 38 | 39 | @end 40 | 41 | static NSString *const defaultAddress = @"https://www.apple.com"; 42 | 43 | @implementation KINWebBrowserExampleViewController 44 | 45 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 46 | { 47 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 48 | if (self) { 49 | // Custom initialization 50 | } 51 | return self; 52 | } 53 | 54 | - (void)viewDidLoad 55 | { 56 | [super viewDidLoad]; 57 | // Do any additional setup after loading the view from its nib. 58 | 59 | self.navigationItem.title = @""; 60 | 61 | [self.navigationController setToolbarHidden:YES]; 62 | [self.navigationController setNavigationBarHidden:YES]; 63 | 64 | self.navigationController.navigationBar.translucent = YES; 65 | self.navigationController.toolbar.translucent = YES; 66 | 67 | 68 | } 69 | 70 | - (void)didReceiveMemoryWarning 71 | { 72 | [super didReceiveMemoryWarning]; 73 | // Dispose of any resources that can be recreated. 74 | } 75 | 76 | #pragma mark - KINWebBrowserDelegate Protocol Implementation 77 | 78 | - (void)webBrowser:(KINWebBrowserViewController *)webBrowser didStartLoadingURL:(NSURL *)URL { 79 | NSLog(@"Started Loading URL : %@", URL); 80 | } 81 | 82 | - (void)webBrowser:(KINWebBrowserViewController *)webBrowser didFinishLoadingURL:(NSURL *)URL { 83 | NSLog(@"Finished Loading URL : %@", URL); 84 | } 85 | 86 | - (void)webBrowser:(KINWebBrowserViewController *)webBrowser didFailToLoadURL:(NSURL *)URL withError:(NSError *)error { 87 | NSLog(@"Failed To Load URL : %@ With Error: %@", URL, error); 88 | } 89 | 90 | - (void)webBrowserViewControllerWillDismiss:(KINWebBrowserViewController*)viewController { 91 | NSLog(@"View Controller will dismiss: %@", viewController); 92 | 93 | } 94 | 95 | 96 | #pragma mark - IBActions 97 | 98 | - (IBAction)pushButtonPressed:(id)sender { 99 | KINWebBrowserViewController *webBrowser = [KINWebBrowserViewController webBrowser]; 100 | [webBrowser setDelegate:self]; 101 | [self.navigationController pushViewController:webBrowser animated:YES]; 102 | [webBrowser loadURLString:defaultAddress]; 103 | } 104 | 105 | - (IBAction)presentButtonPressed:(id)sender { 106 | UINavigationController *webBrowserNavigationController = [KINWebBrowserViewController navigationControllerWithWebBrowser]; 107 | KINWebBrowserViewController *webBrowser = [webBrowserNavigationController rootWebBrowser]; 108 | [webBrowser setDelegate:self]; 109 | webBrowser.showsURLInNavigationBar = YES; 110 | webBrowser.tintColor = [UIColor whiteColor]; 111 | webBrowser.barTintColor = [UIColor colorWithRed:102.0f/255.0f green:204.0f/255.0f blue:51.0f/255.0f alpha:1.0f]; 112 | webBrowser.showsPageTitleInNavigationBar = NO; 113 | webBrowser.showsURLInNavigationBar = NO; 114 | [self presentViewController:webBrowserNavigationController animated:YES completion:nil]; 115 | 116 | [webBrowser loadURLString:defaultAddress]; 117 | } 118 | @end 119 | -------------------------------------------------------------------------------- /KINWebBrowser/KINWebBrowserViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // KINWebBrowserViewController.h 3 | // 4 | // KINWebBrowser 5 | // 6 | // Created by David F. Muir V 7 | // dfmuir@gmail.com 8 | // Co-Founder & Engineer at Kinwa, Inc. 9 | // http://www.kinwa.co 10 | // 11 | // The MIT License (MIT) 12 | // 13 | // Copyright (c) 2014 David Muir 14 | // 15 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | // this software and associated documentation files (the "Software"), to deal in 17 | // the Software without restriction, including without limitation the rights to 18 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 19 | // the Software, and to permit persons to whom the Software is furnished to do so, 20 | // subject to the following conditions: 21 | // 22 | // The above copyright notice and this permission notice shall be included in all 23 | // copies or substantial portions of the Software. 24 | // 25 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 27 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 28 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 29 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | // 32 | 33 | #import 34 | #import 35 | 36 | @class KINWebBrowserViewController; 37 | 38 | /* 39 | 40 | UINavigationController+KINWebBrowserWrapper category enables access to casted KINWebBroswerViewController when set as rootViewController of UINavigationController 41 | 42 | */ 43 | @interface UINavigationController(KINWebBrowser) 44 | 45 | // Returns rootViewController casted as KINWebBrowserViewController 46 | - (KINWebBrowserViewController *)rootWebBrowser; 47 | 48 | @end 49 | 50 | 51 | 52 | @protocol KINWebBrowserDelegate 53 | @optional 54 | - (void)webBrowser:(KINWebBrowserViewController *)webBrowser didStartLoadingURL:(NSURL *)URL; 55 | - (void)webBrowser:(KINWebBrowserViewController *)webBrowser didFinishLoadingURL:(NSURL *)URL; 56 | - (void)webBrowser:(KINWebBrowserViewController *)webBrowser didFailToLoadURL:(NSURL *)URL error:(NSError *)error; 57 | - (void)webBrowserViewControllerWillDismiss:(KINWebBrowserViewController*)viewController; 58 | @end 59 | 60 | 61 | /* 62 | 63 | KINWebBrowserViewController is designed to be used inside of a UINavigationController. 64 | For convenience, two sets of static initializers are available. 65 | 66 | */ 67 | @interface KINWebBrowserViewController : UIViewController 68 | 69 | #pragma mark - Public Properties 70 | 71 | @property (nonatomic, weak) id delegate; 72 | 73 | // The main and only UIProgressView 74 | @property (nonatomic, strong) UIProgressView *progressView; 75 | 76 | // The web views 77 | // Depending on the version of iOS, one of these will be set 78 | @property (nonatomic, strong) WKWebView *wkWebView; 79 | @property (nonatomic, strong) UIWebView *uiWebView; 80 | 81 | - (id)initWithConfiguration:(WKWebViewConfiguration *)configuration NS_AVAILABLE_IOS(8_0); 82 | 83 | #pragma mark - Static Initializers 84 | 85 | /* 86 | Initialize a basic KINWebBrowserViewController instance for push onto navigation stack 87 | 88 | Ideal for use with UINavigationController pushViewController:animated: or initWithRootViewController: 89 | 90 | Optionally specify KINWebBrowser options or WKWebConfiguration 91 | */ 92 | 93 | + (KINWebBrowserViewController *)webBrowser; 94 | + (KINWebBrowserViewController *)webBrowserWithConfiguration:(WKWebViewConfiguration *)configuration NS_AVAILABLE_IOS(8_0); 95 | 96 | /* 97 | Initialize a UINavigationController with a KINWebBrowserViewController for modal presentation. 98 | 99 | Ideal for use with presentViewController:animated: 100 | 101 | Optionally specify KINWebBrowser options or WKWebConfiguration 102 | */ 103 | 104 | + (UINavigationController *)navigationControllerWithWebBrowser; 105 | + (UINavigationController *)navigationControllerWithWebBrowserWithConfiguration:(WKWebViewConfiguration *)configuration NS_AVAILABLE_IOS(8_0); 106 | 107 | 108 | @property (nonatomic, strong) UIBarButtonItem *actionButton; 109 | @property (nonatomic, strong) UIColor *tintColor; 110 | @property (nonatomic, strong) UIColor *barTintColor; 111 | @property (nonatomic, assign) BOOL actionButtonHidden; 112 | @property (nonatomic, assign) BOOL showsURLInNavigationBar; 113 | @property (nonatomic, assign) BOOL showsPageTitleInNavigationBar; 114 | 115 | //Allow for custom activities in the browser by populating this optional array 116 | @property (nonatomic, strong) NSArray *customActivityItems; 117 | 118 | #pragma mark - Public Interface 119 | 120 | 121 | // Load a NSURLURLRequest to web view 122 | // Can be called any time after initialization 123 | - (void)loadRequest:(NSURLRequest *)request; 124 | 125 | // Load a NSURL to web view 126 | // Can be called any time after initialization 127 | - (void)loadURL:(NSURL *)URL; 128 | 129 | // Loads a URL as NSString to web view 130 | // Can be called any time after initialization 131 | - (void)loadURLString:(NSString *)URLString; 132 | 133 | 134 | // Loads an string containing HTML to web view 135 | // Can be called any time after initialization 136 | - (void)loadHTMLString:(NSString *)HTMLString; 137 | 138 | @end 139 | 140 | -------------------------------------------------------------------------------- /ExampleProject/KINWebBrowserExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0B4A989B6C1762F306885B5D /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D246F90867446D07C788DCE /* libPods.a */; }; 11 | 3BBECF2918A1E58D00A2499D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BBECF2818A1E58D00A2499D /* Foundation.framework */; }; 12 | 3BBECF2B18A1E58D00A2499D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BBECF2A18A1E58D00A2499D /* CoreGraphics.framework */; }; 13 | 3BBECF2D18A1E58D00A2499D /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BBECF2C18A1E58D00A2499D /* UIKit.framework */; }; 14 | 3BBECF3318A1E58D00A2499D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3BBECF3118A1E58D00A2499D /* InfoPlist.strings */; }; 15 | 3BBECF3518A1E58D00A2499D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBECF3418A1E58D00A2499D /* main.m */; }; 16 | 3BBECF3918A1E58D00A2499D /* KINAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBECF3818A1E58D00A2499D /* KINAppDelegate.m */; }; 17 | 3BBECF3B18A1E58D00A2499D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3BBECF3A18A1E58D00A2499D /* Images.xcassets */; }; 18 | 3BBECF4218A1E58D00A2499D /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BBECF4118A1E58D00A2499D /* XCTest.framework */; }; 19 | 3BBECF4318A1E58E00A2499D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BBECF2818A1E58D00A2499D /* Foundation.framework */; }; 20 | 3BBECF4418A1E58E00A2499D /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BBECF2C18A1E58D00A2499D /* UIKit.framework */; }; 21 | 3BBECF4C18A1E58E00A2499D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3BBECF4A18A1E58E00A2499D /* InfoPlist.strings */; }; 22 | 3BBECF4E18A1E58E00A2499D /* KINWebBrowserExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBECF4D18A1E58E00A2499D /* KINWebBrowserExampleTests.m */; }; 23 | 3BBECF6518A1EAB100A2499D /* KINWebBrowserExampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBECF6318A1EAB100A2499D /* KINWebBrowserExampleViewController.m */; }; 24 | 3BBECF6618A1EAB100A2499D /* KINWebBrowserExampleViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3BBECF6418A1EAB100A2499D /* KINWebBrowserExampleViewController.xib */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | 3BBECF4518A1E58E00A2499D /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = 3BBECF1D18A1E58D00A2499D /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = 3BBECF2418A1E58D00A2499D; 33 | remoteInfo = KINWebBrowserExample; 34 | }; 35 | /* End PBXContainerItemProxy section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | 0D66287F09CB3E898333BDB8 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 39 | 3B57DAB619E11FAB00C499B5 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 40 | 3BBECF2518A1E58D00A2499D /* KINWebBrowserExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KINWebBrowserExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 3BBECF2818A1E58D00A2499D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 42 | 3BBECF2A18A1E58D00A2499D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 43 | 3BBECF2C18A1E58D00A2499D /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 44 | 3BBECF3018A1E58D00A2499D /* KINWebBrowserExample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "KINWebBrowserExample-Info.plist"; sourceTree = ""; }; 45 | 3BBECF3218A1E58D00A2499D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 46 | 3BBECF3418A1E58D00A2499D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 47 | 3BBECF3618A1E58D00A2499D /* KINWebBrowserExample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "KINWebBrowserExample-Prefix.pch"; sourceTree = ""; }; 48 | 3BBECF3718A1E58D00A2499D /* KINAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KINAppDelegate.h; sourceTree = ""; }; 49 | 3BBECF3818A1E58D00A2499D /* KINAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KINAppDelegate.m; sourceTree = ""; }; 50 | 3BBECF3A18A1E58D00A2499D /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 51 | 3BBECF4018A1E58D00A2499D /* KINWebBrowserExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KINWebBrowserExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | 3BBECF4118A1E58D00A2499D /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 53 | 3BBECF4918A1E58E00A2499D /* KINWebBrowserExampleTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "KINWebBrowserExampleTests-Info.plist"; sourceTree = ""; }; 54 | 3BBECF4B18A1E58E00A2499D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 55 | 3BBECF4D18A1E58E00A2499D /* KINWebBrowserExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KINWebBrowserExampleTests.m; sourceTree = ""; }; 56 | 3BBECF6218A1EAB100A2499D /* KINWebBrowserExampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KINWebBrowserExampleViewController.h; sourceTree = ""; }; 57 | 3BBECF6318A1EAB100A2499D /* KINWebBrowserExampleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KINWebBrowserExampleViewController.m; sourceTree = ""; }; 58 | 3BBECF6418A1EAB100A2499D /* KINWebBrowserExampleViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = KINWebBrowserExampleViewController.xib; sourceTree = ""; }; 59 | 4D246F90867446D07C788DCE /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | E95061206B0428F84E5EAF94 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 61 | /* End PBXFileReference section */ 62 | 63 | /* Begin PBXFrameworksBuildPhase section */ 64 | 3BBECF2218A1E58D00A2499D /* Frameworks */ = { 65 | isa = PBXFrameworksBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | 3BBECF2B18A1E58D00A2499D /* CoreGraphics.framework in Frameworks */, 69 | 3BBECF2D18A1E58D00A2499D /* UIKit.framework in Frameworks */, 70 | 3BBECF2918A1E58D00A2499D /* Foundation.framework in Frameworks */, 71 | 0B4A989B6C1762F306885B5D /* libPods.a in Frameworks */, 72 | ); 73 | runOnlyForDeploymentPostprocessing = 0; 74 | }; 75 | 3BBECF3D18A1E58D00A2499D /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | 3BBECF4218A1E58D00A2499D /* XCTest.framework in Frameworks */, 80 | 3BBECF4418A1E58E00A2499D /* UIKit.framework in Frameworks */, 81 | 3BBECF4318A1E58E00A2499D /* Foundation.framework in Frameworks */, 82 | ); 83 | runOnlyForDeploymentPostprocessing = 0; 84 | }; 85 | /* End PBXFrameworksBuildPhase section */ 86 | 87 | /* Begin PBXGroup section */ 88 | 3BBECF1C18A1E58D00A2499D = { 89 | isa = PBXGroup; 90 | children = ( 91 | 3BBECF2E18A1E58D00A2499D /* KINWebBrowserExample */, 92 | 3BBECF4718A1E58E00A2499D /* KINWebBrowserExampleTests */, 93 | 3BBECF2718A1E58D00A2499D /* Frameworks */, 94 | 3BBECF2618A1E58D00A2499D /* Products */, 95 | F41A3D371A44A50919509CDE /* Pods */, 96 | ); 97 | sourceTree = ""; 98 | }; 99 | 3BBECF2618A1E58D00A2499D /* Products */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 3BBECF2518A1E58D00A2499D /* KINWebBrowserExample.app */, 103 | 3BBECF4018A1E58D00A2499D /* KINWebBrowserExampleTests.xctest */, 104 | ); 105 | name = Products; 106 | sourceTree = ""; 107 | }; 108 | 3BBECF2718A1E58D00A2499D /* Frameworks */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 3B57DAB619E11FAB00C499B5 /* WebKit.framework */, 112 | 3BBECF2818A1E58D00A2499D /* Foundation.framework */, 113 | 3BBECF2A18A1E58D00A2499D /* CoreGraphics.framework */, 114 | 3BBECF2C18A1E58D00A2499D /* UIKit.framework */, 115 | 3BBECF4118A1E58D00A2499D /* XCTest.framework */, 116 | 4D246F90867446D07C788DCE /* libPods.a */, 117 | ); 118 | name = Frameworks; 119 | sourceTree = ""; 120 | }; 121 | 3BBECF2E18A1E58D00A2499D /* KINWebBrowserExample */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 3BBECF3718A1E58D00A2499D /* KINAppDelegate.h */, 125 | 3BBECF3818A1E58D00A2499D /* KINAppDelegate.m */, 126 | 3BBECF6218A1EAB100A2499D /* KINWebBrowserExampleViewController.h */, 127 | 3BBECF6318A1EAB100A2499D /* KINWebBrowserExampleViewController.m */, 128 | 3BBECF6418A1EAB100A2499D /* KINWebBrowserExampleViewController.xib */, 129 | 3BBECF3A18A1E58D00A2499D /* Images.xcassets */, 130 | 3BBECF2F18A1E58D00A2499D /* Supporting Files */, 131 | ); 132 | path = KINWebBrowserExample; 133 | sourceTree = ""; 134 | }; 135 | 3BBECF2F18A1E58D00A2499D /* Supporting Files */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 3BBECF3018A1E58D00A2499D /* KINWebBrowserExample-Info.plist */, 139 | 3BBECF3118A1E58D00A2499D /* InfoPlist.strings */, 140 | 3BBECF3418A1E58D00A2499D /* main.m */, 141 | 3BBECF3618A1E58D00A2499D /* KINWebBrowserExample-Prefix.pch */, 142 | ); 143 | name = "Supporting Files"; 144 | sourceTree = ""; 145 | }; 146 | 3BBECF4718A1E58E00A2499D /* KINWebBrowserExampleTests */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | 3BBECF4D18A1E58E00A2499D /* KINWebBrowserExampleTests.m */, 150 | 3BBECF4818A1E58E00A2499D /* Supporting Files */, 151 | ); 152 | path = KINWebBrowserExampleTests; 153 | sourceTree = ""; 154 | }; 155 | 3BBECF4818A1E58E00A2499D /* Supporting Files */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | 3BBECF4918A1E58E00A2499D /* KINWebBrowserExampleTests-Info.plist */, 159 | 3BBECF4A18A1E58E00A2499D /* InfoPlist.strings */, 160 | ); 161 | name = "Supporting Files"; 162 | sourceTree = ""; 163 | }; 164 | F41A3D371A44A50919509CDE /* Pods */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | E95061206B0428F84E5EAF94 /* Pods.debug.xcconfig */, 168 | 0D66287F09CB3E898333BDB8 /* Pods.release.xcconfig */, 169 | ); 170 | name = Pods; 171 | sourceTree = ""; 172 | }; 173 | /* End PBXGroup section */ 174 | 175 | /* Begin PBXNativeTarget section */ 176 | 3BBECF2418A1E58D00A2499D /* KINWebBrowserExample */ = { 177 | isa = PBXNativeTarget; 178 | buildConfigurationList = 3BBECF5118A1E58E00A2499D /* Build configuration list for PBXNativeTarget "KINWebBrowserExample" */; 179 | buildPhases = ( 180 | 6F51916B9AD244238CE3E060 /* Check Pods Manifest.lock */, 181 | 3BBECF2118A1E58D00A2499D /* Sources */, 182 | 3BBECF2218A1E58D00A2499D /* Frameworks */, 183 | 3BBECF2318A1E58D00A2499D /* Resources */, 184 | F23BEC6F0D11442D85D78196 /* Copy Pods Resources */, 185 | ); 186 | buildRules = ( 187 | ); 188 | dependencies = ( 189 | ); 190 | name = KINWebBrowserExample; 191 | productName = KINWebBrowserExample; 192 | productReference = 3BBECF2518A1E58D00A2499D /* KINWebBrowserExample.app */; 193 | productType = "com.apple.product-type.application"; 194 | }; 195 | 3BBECF3F18A1E58D00A2499D /* KINWebBrowserExampleTests */ = { 196 | isa = PBXNativeTarget; 197 | buildConfigurationList = 3BBECF5418A1E58E00A2499D /* Build configuration list for PBXNativeTarget "KINWebBrowserExampleTests" */; 198 | buildPhases = ( 199 | 3BBECF3C18A1E58D00A2499D /* Sources */, 200 | 3BBECF3D18A1E58D00A2499D /* Frameworks */, 201 | 3BBECF3E18A1E58D00A2499D /* Resources */, 202 | ); 203 | buildRules = ( 204 | ); 205 | dependencies = ( 206 | 3BBECF4618A1E58E00A2499D /* PBXTargetDependency */, 207 | ); 208 | name = KINWebBrowserExampleTests; 209 | productName = KINWebBrowserExampleTests; 210 | productReference = 3BBECF4018A1E58D00A2499D /* KINWebBrowserExampleTests.xctest */; 211 | productType = "com.apple.product-type.bundle.unit-test"; 212 | }; 213 | /* End PBXNativeTarget section */ 214 | 215 | /* Begin PBXProject section */ 216 | 3BBECF1D18A1E58D00A2499D /* Project object */ = { 217 | isa = PBXProject; 218 | attributes = { 219 | CLASSPREFIX = KIN; 220 | LastUpgradeCheck = 0600; 221 | ORGANIZATIONNAME = "Kinwa, Inc."; 222 | TargetAttributes = { 223 | 3BBECF3F18A1E58D00A2499D = { 224 | TestTargetID = 3BBECF2418A1E58D00A2499D; 225 | }; 226 | }; 227 | }; 228 | buildConfigurationList = 3BBECF2018A1E58D00A2499D /* Build configuration list for PBXProject "KINWebBrowserExample" */; 229 | compatibilityVersion = "Xcode 3.2"; 230 | developmentRegion = English; 231 | hasScannedForEncodings = 0; 232 | knownRegions = ( 233 | en, 234 | ); 235 | mainGroup = 3BBECF1C18A1E58D00A2499D; 236 | productRefGroup = 3BBECF2618A1E58D00A2499D /* Products */; 237 | projectDirPath = ""; 238 | projectRoot = ""; 239 | targets = ( 240 | 3BBECF2418A1E58D00A2499D /* KINWebBrowserExample */, 241 | 3BBECF3F18A1E58D00A2499D /* KINWebBrowserExampleTests */, 242 | ); 243 | }; 244 | /* End PBXProject section */ 245 | 246 | /* Begin PBXResourcesBuildPhase section */ 247 | 3BBECF2318A1E58D00A2499D /* Resources */ = { 248 | isa = PBXResourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | 3BBECF6618A1EAB100A2499D /* KINWebBrowserExampleViewController.xib in Resources */, 252 | 3BBECF3318A1E58D00A2499D /* InfoPlist.strings in Resources */, 253 | 3BBECF3B18A1E58D00A2499D /* Images.xcassets in Resources */, 254 | ); 255 | runOnlyForDeploymentPostprocessing = 0; 256 | }; 257 | 3BBECF3E18A1E58D00A2499D /* Resources */ = { 258 | isa = PBXResourcesBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | 3BBECF4C18A1E58E00A2499D /* InfoPlist.strings in Resources */, 262 | ); 263 | runOnlyForDeploymentPostprocessing = 0; 264 | }; 265 | /* End PBXResourcesBuildPhase section */ 266 | 267 | /* Begin PBXShellScriptBuildPhase section */ 268 | 6F51916B9AD244238CE3E060 /* Check Pods Manifest.lock */ = { 269 | isa = PBXShellScriptBuildPhase; 270 | buildActionMask = 2147483647; 271 | files = ( 272 | ); 273 | inputPaths = ( 274 | ); 275 | name = "Check Pods Manifest.lock"; 276 | outputPaths = ( 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | shellPath = /bin/sh; 280 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 281 | showEnvVarsInLog = 0; 282 | }; 283 | F23BEC6F0D11442D85D78196 /* Copy Pods Resources */ = { 284 | isa = PBXShellScriptBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | ); 288 | inputPaths = ( 289 | ); 290 | name = "Copy Pods Resources"; 291 | outputPaths = ( 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | shellPath = /bin/sh; 295 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; 296 | showEnvVarsInLog = 0; 297 | }; 298 | /* End PBXShellScriptBuildPhase section */ 299 | 300 | /* Begin PBXSourcesBuildPhase section */ 301 | 3BBECF2118A1E58D00A2499D /* Sources */ = { 302 | isa = PBXSourcesBuildPhase; 303 | buildActionMask = 2147483647; 304 | files = ( 305 | 3BBECF3518A1E58D00A2499D /* main.m in Sources */, 306 | 3BBECF6518A1EAB100A2499D /* KINWebBrowserExampleViewController.m in Sources */, 307 | 3BBECF3918A1E58D00A2499D /* KINAppDelegate.m in Sources */, 308 | ); 309 | runOnlyForDeploymentPostprocessing = 0; 310 | }; 311 | 3BBECF3C18A1E58D00A2499D /* Sources */ = { 312 | isa = PBXSourcesBuildPhase; 313 | buildActionMask = 2147483647; 314 | files = ( 315 | 3BBECF4E18A1E58E00A2499D /* KINWebBrowserExampleTests.m in Sources */, 316 | ); 317 | runOnlyForDeploymentPostprocessing = 0; 318 | }; 319 | /* End PBXSourcesBuildPhase section */ 320 | 321 | /* Begin PBXTargetDependency section */ 322 | 3BBECF4618A1E58E00A2499D /* PBXTargetDependency */ = { 323 | isa = PBXTargetDependency; 324 | target = 3BBECF2418A1E58D00A2499D /* KINWebBrowserExample */; 325 | targetProxy = 3BBECF4518A1E58E00A2499D /* PBXContainerItemProxy */; 326 | }; 327 | /* End PBXTargetDependency section */ 328 | 329 | /* Begin PBXVariantGroup section */ 330 | 3BBECF3118A1E58D00A2499D /* InfoPlist.strings */ = { 331 | isa = PBXVariantGroup; 332 | children = ( 333 | 3BBECF3218A1E58D00A2499D /* en */, 334 | ); 335 | name = InfoPlist.strings; 336 | sourceTree = ""; 337 | }; 338 | 3BBECF4A18A1E58E00A2499D /* InfoPlist.strings */ = { 339 | isa = PBXVariantGroup; 340 | children = ( 341 | 3BBECF4B18A1E58E00A2499D /* en */, 342 | ); 343 | name = InfoPlist.strings; 344 | sourceTree = ""; 345 | }; 346 | /* End PBXVariantGroup section */ 347 | 348 | /* Begin XCBuildConfiguration section */ 349 | 3BBECF4F18A1E58E00A2499D /* Debug */ = { 350 | isa = XCBuildConfiguration; 351 | buildSettings = { 352 | ALWAYS_SEARCH_USER_PATHS = NO; 353 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 354 | CLANG_CXX_LIBRARY = "libc++"; 355 | CLANG_ENABLE_MODULES = YES; 356 | CLANG_ENABLE_OBJC_ARC = YES; 357 | CLANG_WARN_BOOL_CONVERSION = YES; 358 | CLANG_WARN_CONSTANT_CONVERSION = YES; 359 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 360 | CLANG_WARN_EMPTY_BODY = YES; 361 | CLANG_WARN_ENUM_CONVERSION = YES; 362 | CLANG_WARN_INT_CONVERSION = YES; 363 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 364 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 365 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 366 | COPY_PHASE_STRIP = NO; 367 | GCC_C_LANGUAGE_STANDARD = gnu99; 368 | GCC_DYNAMIC_NO_PIC = NO; 369 | GCC_OPTIMIZATION_LEVEL = 0; 370 | GCC_PREPROCESSOR_DEFINITIONS = ( 371 | "DEBUG=1", 372 | "$(inherited)", 373 | ); 374 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 375 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 376 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 377 | GCC_WARN_UNDECLARED_SELECTOR = YES; 378 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 379 | GCC_WARN_UNUSED_FUNCTION = YES; 380 | GCC_WARN_UNUSED_VARIABLE = YES; 381 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 382 | ONLY_ACTIVE_ARCH = YES; 383 | SDKROOT = iphoneos; 384 | TARGETED_DEVICE_FAMILY = "1,2"; 385 | }; 386 | name = Debug; 387 | }; 388 | 3BBECF5018A1E58E00A2499D /* Release */ = { 389 | isa = XCBuildConfiguration; 390 | buildSettings = { 391 | ALWAYS_SEARCH_USER_PATHS = NO; 392 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 393 | CLANG_CXX_LIBRARY = "libc++"; 394 | CLANG_ENABLE_MODULES = YES; 395 | CLANG_ENABLE_OBJC_ARC = YES; 396 | CLANG_WARN_BOOL_CONVERSION = YES; 397 | CLANG_WARN_CONSTANT_CONVERSION = YES; 398 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 399 | CLANG_WARN_EMPTY_BODY = YES; 400 | CLANG_WARN_ENUM_CONVERSION = YES; 401 | CLANG_WARN_INT_CONVERSION = YES; 402 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 403 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 404 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 405 | COPY_PHASE_STRIP = YES; 406 | ENABLE_NS_ASSERTIONS = NO; 407 | GCC_C_LANGUAGE_STANDARD = gnu99; 408 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 409 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 410 | GCC_WARN_UNDECLARED_SELECTOR = YES; 411 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 412 | GCC_WARN_UNUSED_FUNCTION = YES; 413 | GCC_WARN_UNUSED_VARIABLE = YES; 414 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 415 | SDKROOT = iphoneos; 416 | TARGETED_DEVICE_FAMILY = "1,2"; 417 | VALIDATE_PRODUCT = YES; 418 | }; 419 | name = Release; 420 | }; 421 | 3BBECF5218A1E58E00A2499D /* Debug */ = { 422 | isa = XCBuildConfiguration; 423 | baseConfigurationReference = E95061206B0428F84E5EAF94 /* Pods.debug.xcconfig */; 424 | buildSettings = { 425 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 426 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 427 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 428 | GCC_PREFIX_HEADER = "KINWebBrowserExample/KINWebBrowserExample-Prefix.pch"; 429 | INFOPLIST_FILE = "KINWebBrowserExample/KINWebBrowserExample-Info.plist"; 430 | PRODUCT_NAME = "$(TARGET_NAME)"; 431 | WRAPPER_EXTENSION = app; 432 | }; 433 | name = Debug; 434 | }; 435 | 3BBECF5318A1E58E00A2499D /* Release */ = { 436 | isa = XCBuildConfiguration; 437 | baseConfigurationReference = 0D66287F09CB3E898333BDB8 /* Pods.release.xcconfig */; 438 | buildSettings = { 439 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 440 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 441 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 442 | GCC_PREFIX_HEADER = "KINWebBrowserExample/KINWebBrowserExample-Prefix.pch"; 443 | INFOPLIST_FILE = "KINWebBrowserExample/KINWebBrowserExample-Info.plist"; 444 | PRODUCT_NAME = "$(TARGET_NAME)"; 445 | WRAPPER_EXTENSION = app; 446 | }; 447 | name = Release; 448 | }; 449 | 3BBECF5518A1E58E00A2499D /* Debug */ = { 450 | isa = XCBuildConfiguration; 451 | buildSettings = { 452 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/KINWebBrowserExample.app/KINWebBrowserExample"; 453 | FRAMEWORK_SEARCH_PATHS = ( 454 | "$(SDKROOT)/Developer/Library/Frameworks", 455 | "$(inherited)", 456 | "$(DEVELOPER_FRAMEWORKS_DIR)", 457 | ); 458 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 459 | GCC_PREFIX_HEADER = "KINWebBrowserExample/KINWebBrowserExample-Prefix.pch"; 460 | GCC_PREPROCESSOR_DEFINITIONS = ( 461 | "DEBUG=1", 462 | "$(inherited)", 463 | ); 464 | INFOPLIST_FILE = "KINWebBrowserExampleTests/KINWebBrowserExampleTests-Info.plist"; 465 | PRODUCT_NAME = "$(TARGET_NAME)"; 466 | TEST_HOST = "$(BUNDLE_LOADER)"; 467 | WRAPPER_EXTENSION = xctest; 468 | }; 469 | name = Debug; 470 | }; 471 | 3BBECF5618A1E58E00A2499D /* Release */ = { 472 | isa = XCBuildConfiguration; 473 | buildSettings = { 474 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/KINWebBrowserExample.app/KINWebBrowserExample"; 475 | FRAMEWORK_SEARCH_PATHS = ( 476 | "$(SDKROOT)/Developer/Library/Frameworks", 477 | "$(inherited)", 478 | "$(DEVELOPER_FRAMEWORKS_DIR)", 479 | ); 480 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 481 | GCC_PREFIX_HEADER = "KINWebBrowserExample/KINWebBrowserExample-Prefix.pch"; 482 | INFOPLIST_FILE = "KINWebBrowserExampleTests/KINWebBrowserExampleTests-Info.plist"; 483 | PRODUCT_NAME = "$(TARGET_NAME)"; 484 | TEST_HOST = "$(BUNDLE_LOADER)"; 485 | WRAPPER_EXTENSION = xctest; 486 | }; 487 | name = Release; 488 | }; 489 | /* End XCBuildConfiguration section */ 490 | 491 | /* Begin XCConfigurationList section */ 492 | 3BBECF2018A1E58D00A2499D /* Build configuration list for PBXProject "KINWebBrowserExample" */ = { 493 | isa = XCConfigurationList; 494 | buildConfigurations = ( 495 | 3BBECF4F18A1E58E00A2499D /* Debug */, 496 | 3BBECF5018A1E58E00A2499D /* Release */, 497 | ); 498 | defaultConfigurationIsVisible = 0; 499 | defaultConfigurationName = Release; 500 | }; 501 | 3BBECF5118A1E58E00A2499D /* Build configuration list for PBXNativeTarget "KINWebBrowserExample" */ = { 502 | isa = XCConfigurationList; 503 | buildConfigurations = ( 504 | 3BBECF5218A1E58E00A2499D /* Debug */, 505 | 3BBECF5318A1E58E00A2499D /* Release */, 506 | ); 507 | defaultConfigurationIsVisible = 0; 508 | defaultConfigurationName = Release; 509 | }; 510 | 3BBECF5418A1E58E00A2499D /* Build configuration list for PBXNativeTarget "KINWebBrowserExampleTests" */ = { 511 | isa = XCConfigurationList; 512 | buildConfigurations = ( 513 | 3BBECF5518A1E58E00A2499D /* Debug */, 514 | 3BBECF5618A1E58E00A2499D /* Release */, 515 | ); 516 | defaultConfigurationIsVisible = 0; 517 | defaultConfigurationName = Release; 518 | }; 519 | /* End XCConfigurationList section */ 520 | }; 521 | rootObject = 3BBECF1D18A1E58D00A2499D /* Project object */; 522 | } 523 | -------------------------------------------------------------------------------- /KINWebBrowser/KINWebBrowserViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // KINWebBrowserViewController.m 3 | // 4 | // KINWebBrowser 5 | // 6 | // Created by David F. Muir V 7 | // dfmuir@gmail.com 8 | // Co-Founder & Engineer at Kinwa, Inc. 9 | // http://www.kinwa.co 10 | // 11 | // The MIT License (MIT) 12 | // 13 | // Copyright (c) 2014 David Muir 14 | // 15 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | // this software and associated documentation files (the "Software"), to deal in 17 | // the Software without restriction, including without limitation the rights to 18 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 19 | // the Software, and to permit persons to whom the Software is furnished to do so, 20 | // subject to the following conditions: 21 | // 22 | // The above copyright notice and this permission notice shall be included in all 23 | // copies or substantial portions of the Software. 24 | // 25 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 27 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 28 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 29 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | // 32 | 33 | #import "KINWebBrowserViewController.h" 34 | 35 | #import "TUSafariActivity.h" 36 | #import "ARChromeActivity.h" 37 | 38 | static void *KINWebBrowserContext = &KINWebBrowserContext; 39 | 40 | @interface KINWebBrowserViewController () 41 | 42 | @property (nonatomic, assign) BOOL previousNavigationControllerToolbarHidden, previousNavigationControllerNavigationBarHidden; 43 | @property (nonatomic, strong) UIBarButtonItem *backButton, *forwardButton, *refreshButton, *stopButton, *fixedSeparator, *flexibleSeparator; 44 | @property (nonatomic, strong) NSTimer *fakeProgressTimer; 45 | @property (nonatomic, strong) UIPopoverController *actionPopoverController; 46 | @property (nonatomic, assign) BOOL uiWebViewIsLoading; 47 | @property (nonatomic, strong) NSURL *uiWebViewCurrentURL; 48 | @property (nonatomic, strong) NSURL *URLToLaunchWithPermission; 49 | @property (nonatomic, strong) UIAlertView *externalAppPermissionAlertView; 50 | 51 | @end 52 | 53 | @implementation KINWebBrowserViewController 54 | 55 | #pragma mark - Static Initializers 56 | 57 | + (KINWebBrowserViewController *)webBrowser { 58 | KINWebBrowserViewController *webBrowserViewController = [KINWebBrowserViewController webBrowserWithConfiguration:nil]; 59 | return webBrowserViewController; 60 | } 61 | 62 | + (KINWebBrowserViewController *)webBrowserWithConfiguration:(WKWebViewConfiguration *)configuration { 63 | KINWebBrowserViewController *webBrowserViewController = [[self alloc] initWithConfiguration:configuration]; 64 | return webBrowserViewController; 65 | } 66 | 67 | + (UINavigationController *)navigationControllerWithWebBrowser { 68 | KINWebBrowserViewController *webBrowserViewController = [[self alloc] initWithConfiguration:nil]; 69 | return [KINWebBrowserViewController navigationControllerWithBrowser:webBrowserViewController]; 70 | } 71 | 72 | + (UINavigationController *)navigationControllerWithWebBrowserWithConfiguration:(WKWebViewConfiguration *)configuration { 73 | KINWebBrowserViewController *webBrowserViewController = [[self alloc] initWithConfiguration:configuration]; 74 | return [KINWebBrowserViewController navigationControllerWithBrowser:webBrowserViewController]; 75 | } 76 | 77 | + (UINavigationController *)navigationControllerWithBrowser:(KINWebBrowserViewController *)webBrowser { 78 | UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:webBrowser action:@selector(doneButtonPressed:)]; 79 | [webBrowser.navigationItem setRightBarButtonItem:doneButton]; 80 | 81 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:webBrowser]; 82 | return navigationController; 83 | } 84 | 85 | #pragma mark - Initializers 86 | 87 | - (id)init { 88 | return [self initWithConfiguration:nil]; 89 | } 90 | 91 | - (id)initWithConfiguration:(WKWebViewConfiguration *)configuration { 92 | self = [super init]; 93 | if(self) { 94 | if([WKWebView class]) { 95 | if(configuration) { 96 | self.wkWebView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]; 97 | } 98 | else { 99 | self.wkWebView = [[WKWebView alloc] init]; 100 | } 101 | } 102 | else { 103 | self.uiWebView = [[UIWebView alloc] init]; 104 | } 105 | 106 | self.actionButtonHidden = NO; 107 | self.showsURLInNavigationBar = NO; 108 | self.showsPageTitleInNavigationBar = YES; 109 | 110 | self.externalAppPermissionAlertView = [[UIAlertView alloc] initWithTitle:@"Leave this app?" message:@"This web page is trying to open an outside app. Are you sure you want to open it?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Open App", nil]; 111 | 112 | } 113 | return self; 114 | } 115 | 116 | #pragma mark - View Lifecycle 117 | 118 | - (void)viewDidLoad { 119 | [super viewDidLoad]; 120 | 121 | self.previousNavigationControllerToolbarHidden = self.navigationController.toolbarHidden; 122 | self.previousNavigationControllerNavigationBarHidden = self.navigationController.navigationBarHidden; 123 | 124 | if(self.wkWebView) { 125 | [self.wkWebView setFrame:self.view.bounds]; 126 | [self.wkWebView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; 127 | [self.wkWebView setNavigationDelegate:self]; 128 | [self.wkWebView setUIDelegate:self]; 129 | [self.wkWebView setMultipleTouchEnabled:YES]; 130 | [self.wkWebView setAutoresizesSubviews:YES]; 131 | [self.wkWebView.scrollView setAlwaysBounceVertical:YES]; 132 | [self.view addSubview:self.wkWebView]; 133 | 134 | [self.wkWebView addObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress)) options:0 context:KINWebBrowserContext]; 135 | } 136 | else if(self.uiWebView) { 137 | [self.uiWebView setFrame:self.view.bounds]; 138 | [self.uiWebView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; 139 | [self.uiWebView setDelegate:self]; 140 | [self.uiWebView setMultipleTouchEnabled:YES]; 141 | [self.uiWebView setAutoresizesSubviews:YES]; 142 | [self.uiWebView setScalesPageToFit:YES]; 143 | [self.uiWebView.scrollView setAlwaysBounceVertical:YES]; 144 | [self.view addSubview:self.uiWebView]; 145 | } 146 | 147 | 148 | self.progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; 149 | [self.progressView setTrackTintColor:[UIColor colorWithWhite:1.0f alpha:0.0f]]; 150 | [self.progressView setFrame:CGRectMake(0, self.navigationController.navigationBar.frame.size.height-self.progressView.frame.size.height, self.view.frame.size.width, self.progressView.frame.size.height)]; 151 | [self.progressView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin]; 152 | } 153 | 154 | - (void)viewWillAppear:(BOOL)animated { 155 | [super viewWillAppear:animated]; 156 | 157 | [self.navigationController setNavigationBarHidden:NO animated:YES]; 158 | [self.navigationController setToolbarHidden:NO animated:YES]; 159 | 160 | [self.navigationController.navigationBar addSubview:self.progressView]; 161 | 162 | [self updateToolbarState]; 163 | } 164 | 165 | - (void)viewWillDisappear:(BOOL)animated { 166 | [super viewWillDisappear:animated]; 167 | 168 | [self.navigationController setNavigationBarHidden:self.previousNavigationControllerNavigationBarHidden animated:animated]; 169 | 170 | [self.navigationController setToolbarHidden:self.previousNavigationControllerToolbarHidden animated:animated]; 171 | 172 | [self.uiWebView setDelegate:nil]; 173 | [self.progressView removeFromSuperview]; 174 | } 175 | 176 | #pragma mark - Public Interface 177 | 178 | - (void)loadRequest:(NSURLRequest *)request { 179 | if(self.wkWebView) { 180 | [self.wkWebView loadRequest:request]; 181 | } 182 | else if(self.uiWebView) { 183 | [self.uiWebView loadRequest:request]; 184 | } 185 | } 186 | 187 | - (void)loadURL:(NSURL *)URL { 188 | [self loadRequest:[NSURLRequest requestWithURL:URL]]; 189 | } 190 | 191 | - (void)loadURLString:(NSString *)URLString { 192 | NSURL *URL = [NSURL URLWithString:URLString]; 193 | [self loadURL:URL]; 194 | } 195 | 196 | - (void)loadHTMLString:(NSString *)HTMLString { 197 | if(self.wkWebView) { 198 | [self.wkWebView loadHTMLString:HTMLString baseURL:nil]; 199 | } 200 | else if(self.uiWebView) { 201 | [self.uiWebView loadHTMLString:HTMLString baseURL:nil]; 202 | } 203 | } 204 | 205 | - (void)setTintColor:(UIColor *)tintColor { 206 | _tintColor = tintColor; 207 | [self.progressView setTintColor:tintColor]; 208 | [self.navigationController.navigationBar setTintColor:tintColor]; 209 | [self.navigationController.toolbar setTintColor:tintColor]; 210 | } 211 | 212 | - (void)setBarTintColor:(UIColor *)barTintColor { 213 | _barTintColor = barTintColor; 214 | [self.navigationController.navigationBar setBarTintColor:barTintColor]; 215 | [self.navigationController.toolbar setBarTintColor:barTintColor]; 216 | } 217 | 218 | - (void)setActionButtonHidden:(BOOL)actionButtonHidden { 219 | _actionButtonHidden = actionButtonHidden; 220 | [self updateToolbarState]; 221 | } 222 | 223 | 224 | #pragma mark - UIWebViewDelegate 225 | 226 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { 227 | if(webView == self.uiWebView) { 228 | 229 | if(![self externalAppRequiredToOpenURL:request.URL]) { 230 | self.uiWebViewCurrentURL = request.URL; 231 | self.uiWebViewIsLoading = YES; 232 | [self updateToolbarState]; 233 | 234 | [self fakeProgressViewStartLoading]; 235 | 236 | if([self.delegate respondsToSelector:@selector(webBrowser:didStartLoadingURL:)]) { 237 | [self.delegate webBrowser:self didStartLoadingURL:request.URL]; 238 | } 239 | return YES; 240 | } 241 | else { 242 | [self launchExternalAppWithURL:request.URL]; 243 | return NO; 244 | } 245 | } 246 | return NO; 247 | } 248 | 249 | - (void)webViewDidFinishLoad:(UIWebView *)webView { 250 | if(webView == self.uiWebView) { 251 | if(!self.uiWebView.isLoading) { 252 | self.uiWebViewIsLoading = NO; 253 | [self updateToolbarState]; 254 | 255 | [self fakeProgressBarStopLoading]; 256 | } 257 | 258 | if([self.delegate respondsToSelector:@selector(webBrowser:didFinishLoadingURL:)]) { 259 | [self.delegate webBrowser:self didFinishLoadingURL:self.uiWebView.request.URL]; 260 | } 261 | } 262 | } 263 | 264 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { 265 | if(webView == self.uiWebView) { 266 | if(!self.uiWebView.isLoading) { 267 | self.uiWebViewIsLoading = NO; 268 | [self updateToolbarState]; 269 | 270 | [self fakeProgressBarStopLoading]; 271 | } 272 | if([self.delegate respondsToSelector:@selector(webBrowser:didFailToLoadURL:error:)]) { 273 | [self.delegate webBrowser:self didFailToLoadURL:self.uiWebView.request.URL error:error]; 274 | } 275 | } 276 | } 277 | 278 | #pragma mark - WKNavigationDelegate 279 | 280 | - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { 281 | if(webView == self.wkWebView) { 282 | [self updateToolbarState]; 283 | if([self.delegate respondsToSelector:@selector(webBrowser:didStartLoadingURL:)]) { 284 | [self.delegate webBrowser:self didStartLoadingURL:self.wkWebView.URL]; 285 | } 286 | } 287 | } 288 | 289 | - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { 290 | if(webView == self.wkWebView) { 291 | [self updateToolbarState]; 292 | if([self.delegate respondsToSelector:@selector(webBrowser:didFinishLoadingURL:)]) { 293 | [self.delegate webBrowser:self didFinishLoadingURL:self.wkWebView.URL]; 294 | } 295 | } 296 | } 297 | 298 | - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation 299 | withError:(NSError *)error { 300 | if(webView == self.wkWebView) { 301 | [self updateToolbarState]; 302 | if([self.delegate respondsToSelector:@selector(webBrowser:didFailToLoadURL:error:)]) { 303 | [self.delegate webBrowser:self didFailToLoadURL:self.wkWebView.URL error:error]; 304 | } 305 | } 306 | } 307 | 308 | - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation 309 | withError:(NSError *)error { 310 | if(webView == self.wkWebView) { 311 | [self updateToolbarState]; 312 | if([self.delegate respondsToSelector:@selector(webBrowser:didFailToLoadURL:error:)]) { 313 | [self.delegate webBrowser:self didFailToLoadURL:self.wkWebView.URL error:error]; 314 | } 315 | } 316 | } 317 | 318 | - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { 319 | if(webView == self.wkWebView) { 320 | 321 | NSURL *URL = navigationAction.request.URL; 322 | if(![self externalAppRequiredToOpenURL:URL]) { 323 | if(!navigationAction.targetFrame) { 324 | [self loadURL:URL]; 325 | decisionHandler(WKNavigationActionPolicyCancel); 326 | return; 327 | } 328 | } 329 | else if([[UIApplication sharedApplication] canOpenURL:URL]) { 330 | [self launchExternalAppWithURL:URL]; 331 | decisionHandler(WKNavigationActionPolicyCancel); 332 | return; 333 | } 334 | } 335 | decisionHandler(WKNavigationActionPolicyAllow); 336 | } 337 | 338 | #pragma mark - WKUIDelegate 339 | 340 | - (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{ 341 | if (!navigationAction.targetFrame.isMainFrame) { 342 | [webView loadRequest:navigationAction.request]; 343 | } 344 | return nil; 345 | } 346 | 347 | #pragma mark - Toolbar State 348 | 349 | - (void)updateToolbarState { 350 | 351 | BOOL canGoBack = self.wkWebView.canGoBack || self.uiWebView.canGoBack; 352 | BOOL canGoForward = self.wkWebView.canGoForward || self.uiWebView.canGoForward; 353 | 354 | [self.backButton setEnabled:canGoBack]; 355 | [self.forwardButton setEnabled:canGoForward]; 356 | 357 | if(!self.backButton) { 358 | [self setupToolbarItems]; 359 | } 360 | 361 | NSArray *barButtonItems; 362 | if(self.wkWebView.loading || self.uiWebViewIsLoading) { 363 | barButtonItems = @[self.backButton, self.fixedSeparator, self.forwardButton, self.fixedSeparator, self.stopButton, self.flexibleSeparator]; 364 | 365 | if(self.showsURLInNavigationBar) { 366 | NSString *URLString; 367 | if(self.wkWebView) { 368 | URLString = [self.wkWebView.URL absoluteString]; 369 | } 370 | else if(self.uiWebView) { 371 | URLString = [self.uiWebViewCurrentURL absoluteString]; 372 | } 373 | 374 | URLString = [URLString stringByReplacingOccurrencesOfString:@"http://" withString:@""]; 375 | URLString = [URLString stringByReplacingOccurrencesOfString:@"https://" withString:@""]; 376 | URLString = [URLString substringToIndex:[URLString length]-1]; 377 | self.navigationItem.title = URLString; 378 | } 379 | } 380 | else { 381 | barButtonItems = @[self.backButton, self.fixedSeparator, self.forwardButton, self.fixedSeparator, self.refreshButton, self.flexibleSeparator]; 382 | 383 | if(self.showsPageTitleInNavigationBar) { 384 | if(self.wkWebView) { 385 | self.navigationItem.title = self.wkWebView.title; 386 | } 387 | else if(self.uiWebView) { 388 | self.navigationItem.title = [self.uiWebView stringByEvaluatingJavaScriptFromString:@"document.title"]; 389 | } 390 | } 391 | } 392 | 393 | if(!self.actionButtonHidden) { 394 | NSMutableArray *mutableBarButtonItems = [NSMutableArray arrayWithArray:barButtonItems]; 395 | [mutableBarButtonItems addObject:self.actionButton]; 396 | barButtonItems = [NSArray arrayWithArray:mutableBarButtonItems]; 397 | } 398 | 399 | [self setToolbarItems:barButtonItems animated:YES]; 400 | 401 | self.tintColor = self.tintColor; 402 | self.barTintColor = self.barTintColor; 403 | 404 | 405 | } 406 | 407 | - (void)setupToolbarItems { 408 | NSBundle *bundle = [NSBundle bundleForClass:[KINWebBrowserViewController class]]; 409 | 410 | self.refreshButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(refreshButtonPressed:)]; 411 | self.stopButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop target:self action:@selector(stopButtonPressed:)]; 412 | 413 | UIImage *backbuttonImage = [UIImage imageWithContentsOfFile: [bundle pathForResource:@"backbutton" ofType:@"png"]]; 414 | self.backButton = [[UIBarButtonItem alloc] initWithImage:backbuttonImage style:UIBarButtonItemStylePlain target:self action:@selector(backButtonPressed:)]; 415 | 416 | UIImage *forwardbuttonImage = [UIImage imageWithContentsOfFile: [bundle pathForResource:@"forwardbutton" ofType:@"png"]]; 417 | self.forwardButton = [[UIBarButtonItem alloc] initWithImage:forwardbuttonImage style:UIBarButtonItemStylePlain target:self action:@selector(forwardButtonPressed:)]; 418 | self.actionButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(actionButtonPressed:)]; 419 | self.fixedSeparator = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; 420 | self.fixedSeparator.width = 50.0f; 421 | self.flexibleSeparator = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 422 | } 423 | 424 | #pragma mark - Done Button Action 425 | 426 | - (void)doneButtonPressed:(id)sender { 427 | [self dismissAnimated:YES]; 428 | } 429 | 430 | #pragma mark - UIBarButtonItem Target Action Methods 431 | 432 | - (void)backButtonPressed:(id)sender { 433 | 434 | if(self.wkWebView) { 435 | [self.wkWebView goBack]; 436 | } 437 | else if(self.uiWebView) { 438 | [self.uiWebView goBack]; 439 | } 440 | [self updateToolbarState]; 441 | } 442 | 443 | - (void)forwardButtonPressed:(id)sender { 444 | if(self.wkWebView) { 445 | [self.wkWebView goForward]; 446 | } 447 | else if(self.uiWebView) { 448 | [self.uiWebView goForward]; 449 | } 450 | [self updateToolbarState]; 451 | } 452 | 453 | - (void)refreshButtonPressed:(id)sender { 454 | if(self.wkWebView) { 455 | [self.wkWebView stopLoading]; 456 | [self.wkWebView reload]; 457 | } 458 | else if(self.uiWebView) { 459 | [self.uiWebView stopLoading]; 460 | [self.uiWebView reload]; 461 | } 462 | } 463 | 464 | - (void)stopButtonPressed:(id)sender { 465 | if(self.wkWebView) { 466 | [self.wkWebView stopLoading]; 467 | } 468 | else if(self.uiWebView) { 469 | [self.uiWebView stopLoading]; 470 | } 471 | } 472 | 473 | - (void)actionButtonPressed:(id)sender { 474 | NSURL *URLForActivityItem; 475 | NSString *URLTitle; 476 | if(self.wkWebView) { 477 | URLForActivityItem = self.wkWebView.URL; 478 | URLTitle = self.wkWebView.title; 479 | } 480 | else if(self.uiWebView) { 481 | URLForActivityItem = self.uiWebView.request.URL; 482 | URLTitle = [self.uiWebView stringByEvaluatingJavaScriptFromString:@"document.title"]; 483 | } 484 | if (URLForActivityItem) { 485 | dispatch_async(dispatch_get_main_queue(), ^{ 486 | TUSafariActivity *safariActivity = [[TUSafariActivity alloc] init]; 487 | ARChromeActivity *chromeActivity = [[ARChromeActivity alloc] init]; 488 | 489 | NSMutableArray *activities = [[NSMutableArray alloc] init]; 490 | [activities addObject:safariActivity]; 491 | [activities addObject:chromeActivity]; 492 | if(self.customActivityItems != nil) { 493 | [activities addObjectsFromArray:self.customActivityItems]; 494 | } 495 | 496 | UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:@[URLForActivityItem] applicationActivities:activities]; 497 | 498 | if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { 499 | if(self.actionPopoverController) { 500 | [self.actionPopoverController dismissPopoverAnimated:YES]; 501 | } 502 | self.actionPopoverController = [[UIPopoverController alloc] initWithContentViewController:controller]; 503 | [self.actionPopoverController presentPopoverFromBarButtonItem:self.actionButton permittedArrowDirections: UIPopoverArrowDirectionAny animated:YES]; 504 | } 505 | else { 506 | [self presentViewController:controller animated:YES completion:NULL]; 507 | } 508 | }); 509 | } 510 | } 511 | 512 | 513 | #pragma mark - Estimated Progress KVO (WKWebView) 514 | 515 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 516 | if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))] && object == self.wkWebView) { 517 | [self.progressView setAlpha:1.0f]; 518 | BOOL animated = self.wkWebView.estimatedProgress > self.progressView.progress; 519 | [self.progressView setProgress:self.wkWebView.estimatedProgress animated:animated]; 520 | 521 | // Once complete, fade out UIProgressView 522 | if(self.wkWebView.estimatedProgress >= 1.0f) { 523 | [UIView animateWithDuration:0.3f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{ 524 | [self.progressView setAlpha:0.0f]; 525 | } completion:^(BOOL finished) { 526 | [self.progressView setProgress:0.0f animated:NO]; 527 | }]; 528 | } 529 | } 530 | else { 531 | [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 532 | } 533 | } 534 | 535 | 536 | #pragma mark - Fake Progress Bar Control (UIWebView) 537 | 538 | - (void)fakeProgressViewStartLoading { 539 | [self.progressView setProgress:0.0f animated:NO]; 540 | [self.progressView setAlpha:1.0f]; 541 | 542 | if(!self.fakeProgressTimer) { 543 | self.fakeProgressTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f/60.0f target:self selector:@selector(fakeProgressTimerDidFire:) userInfo:nil repeats:YES]; 544 | } 545 | } 546 | 547 | - (void)fakeProgressBarStopLoading { 548 | if(self.fakeProgressTimer) { 549 | [self.fakeProgressTimer invalidate]; 550 | } 551 | 552 | if(self.progressView) { 553 | [self.progressView setProgress:1.0f animated:YES]; 554 | [UIView animateWithDuration:0.3f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{ 555 | [self.progressView setAlpha:0.0f]; 556 | } completion:^(BOOL finished) { 557 | [self.progressView setProgress:0.0f animated:NO]; 558 | }]; 559 | } 560 | } 561 | 562 | - (void)fakeProgressTimerDidFire:(id)sender { 563 | CGFloat increment = 0.005/(self.progressView.progress + 0.2); 564 | if([self.uiWebView isLoading]) { 565 | CGFloat progress = (self.progressView.progress < 0.75f) ? self.progressView.progress + increment : self.progressView.progress + 0.0005; 566 | if(self.progressView.progress < 0.95) { 567 | [self.progressView setProgress:progress animated:YES]; 568 | } 569 | } 570 | } 571 | 572 | #pragma mark - External App Support 573 | 574 | - (BOOL)externalAppRequiredToOpenURL:(NSURL *)URL { 575 | NSSet *validSchemes = [NSSet setWithArray:@[@"http", @"https"]]; 576 | return ![validSchemes containsObject:URL.scheme]; 577 | } 578 | 579 | - (void)launchExternalAppWithURL:(NSURL *)URL { 580 | self.URLToLaunchWithPermission = URL; 581 | if (![self.externalAppPermissionAlertView isVisible]) { 582 | [self.externalAppPermissionAlertView show]; 583 | } 584 | 585 | } 586 | 587 | #pragma mark - UIAlertViewDelegate 588 | 589 | - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { 590 | if(alertView == self.externalAppPermissionAlertView) { 591 | if(buttonIndex != alertView.cancelButtonIndex) { 592 | [[UIApplication sharedApplication] openURL:self.URLToLaunchWithPermission]; 593 | } 594 | self.URLToLaunchWithPermission = nil; 595 | } 596 | } 597 | 598 | #pragma mark - Dismiss 599 | 600 | - (void)dismissAnimated:(BOOL)animated { 601 | if([self.delegate respondsToSelector:@selector(webBrowserViewControllerWillDismiss:)]) { 602 | [self.delegate webBrowserViewControllerWillDismiss:self]; 603 | } 604 | [self.navigationController dismissViewControllerAnimated:animated completion:nil]; 605 | } 606 | 607 | #pragma mark - Interface Orientation 608 | 609 | - (UIInterfaceOrientationMask)supportedInterfaceOrientations { 610 | return UIInterfaceOrientationMaskAllButUpsideDown; 611 | } 612 | 613 | - (BOOL)shouldAutorotate { 614 | return YES; 615 | } 616 | 617 | #pragma mark - Dealloc 618 | 619 | - (void)dealloc { 620 | [self.uiWebView setDelegate:nil]; 621 | 622 | [self.wkWebView setNavigationDelegate:nil]; 623 | [self.wkWebView setUIDelegate:nil]; 624 | if ([self isViewLoaded]) { 625 | [self.wkWebView removeObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress))]; 626 | } 627 | } 628 | 629 | 630 | @end 631 | 632 | @implementation UINavigationController(KINWebBrowser) 633 | 634 | - (KINWebBrowserViewController *)rootWebBrowser { 635 | UIViewController *rootViewController = [self.viewControllers objectAtIndex:0]; 636 | return (KINWebBrowserViewController *)rootViewController; 637 | } 638 | 639 | @end 640 | --------------------------------------------------------------------------------