├── GTMWebKitExample
├── zh-Hans.lproj
│ ├── Main.strings
│ └── LaunchScreen.strings
├── Assets.xcassets
│ ├── Contents.json
│ ├── Logo.imageset
│ │ ├── logo.png
│ │ ├── wk-2.png
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── wk-1.png
│ │ ├── wk-2.png
│ │ ├── wk-3.png
│ │ ├── wk-4.png
│ │ ├── wk-5.png
│ │ ├── wk-6.png
│ │ ├── wk-7.png
│ │ ├── wk-8.png
│ │ ├── wk.png
│ │ └── Contents.json
│ ├── cus_back.imageset
│ │ ├── icon_cp.png
│ │ ├── icon_cp-1.png
│ │ └── Contents.json
│ └── nav_back.imageset
│ │ ├── nav_back@2x.png
│ │ ├── nav_back@3x.png
│ │ └── Contents.json
├── ScanViewController.swift
├── Info.plist
├── BarcodeScanable.swift
├── Swift Scan
│ ├── LBXScanNetAnimation.swift
│ ├── LBXPermissions.swift
│ ├── LBXScanLineAnimation.swift
│ ├── LBXScanViewStyle.swift
│ ├── LBXScanViewController.swift
│ ├── LBXScanView.swift
│ └── LBXScanWrapper.swift
├── AppDelegate.swift
├── test.html
├── CustomWebViewController.swift
├── ViewController.swift
├── UIWebViewCookiesVC.swift
├── WKWebViewCookiesVC.swift
└── Base.lproj
│ └── LaunchScreen.storyboard
├── logo.png
├── GTMWebKit
├── GTMWebKit.bundle
│ ├── 404@2x.png
│ ├── 404@3x.png
│ ├── back@2x.png
│ ├── back@3x.png
│ ├── forward@2x.png
│ ├── forward@3x.png
│ ├── nav_back@2x.png
│ ├── nav_back@3x.png
│ ├── nosingle@2x.png
│ ├── nosingle@3x.png
│ ├── en.lproj
│ │ ├── Root.strings
│ │ └── Localizable.strings
│ ├── zh-Hans.lproj
│ │ └── Localizable.strings
│ └── Root.plist
├── GTMWebView+Bundle.swift
├── URLConvertible.swift
├── GTMAlertable.swift
├── WeakScriptMessageHandler.swift
├── GTMWebKit.swift
├── Info.plist
├── GTMWebViewCookies.swift
├── GTMWebView+Alert.swift
├── GTMWebControls.swift
├── GTMWebView+WKWebView.swift
└── GTMWebViewController.swift
├── GTMWebKit.podspec
├── LICENSE
├── README.md
└── GTMWebKit.xcodeproj
└── project.pbxproj
/GTMWebKitExample/zh-Hans.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/GTMWebKitExample/zh-Hans.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/logo.png
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/404@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKit/GTMWebKit.bundle/404@2x.png
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/404@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKit/GTMWebKit.bundle/404@3x.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/back@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKit/GTMWebKit.bundle/back@2x.png
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/back@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKit/GTMWebKit.bundle/back@3x.png
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/forward@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKit/GTMWebKit.bundle/forward@2x.png
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/forward@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKit/GTMWebKit.bundle/forward@3x.png
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/nav_back@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKit/GTMWebKit.bundle/nav_back@2x.png
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/nav_back@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKit/GTMWebKit.bundle/nav_back@3x.png
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/nosingle@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKit/GTMWebKit.bundle/nosingle@2x.png
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/nosingle@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKit/GTMWebKit.bundle/nosingle@3x.png
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/en.lproj/Root.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKit/GTMWebKit.bundle/en.lproj/Root.strings
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/Logo.imageset/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/Logo.imageset/logo.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/Logo.imageset/wk-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/Logo.imageset/wk-2.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-1.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-2.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-3.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-4.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-5.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-6.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-7.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk-8.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/wk.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/cus_back.imageset/icon_cp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/cus_back.imageset/icon_cp.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/cus_back.imageset/icon_cp-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/cus_back.imageset/icon_cp-1.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/nav_back.imageset/nav_back@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/nav_back.imageset/nav_back@2x.png
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/nav_back.imageset/nav_back@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GTMYang/GTMWebKit/HEAD/GTMWebKitExample/Assets.xcassets/nav_back.imageset/nav_back@3x.png
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebView+Bundle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GTMWebView+Bundle.swift
3 | // GTMWebKit
4 | //
5 | // Created by luoyang on 2017/10/30.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension GTMWebViewController {
12 |
13 | var sourceBundle: Bundle {
14 | return GTM_bundle()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/Logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "wk-2.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "logo.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/cus_back.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "icon_cp-1.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "icon_cp.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/nav_back.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "nav_back@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "nav_back@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/GTMWebKit/URLConvertible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLConvertible.swift
3 | // GTMWebKit
4 | //
5 | // Created by luoyang on 2017/10/25.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol URLConvertible {
12 | func url() -> URL?
13 | }
14 |
15 | extension String: URLConvertible {
16 | public func url() -> URL? {
17 | return URL.init(string: self)
18 | }
19 | }
20 |
21 | extension URL: URLConvertible {
22 | public func url() -> URL? {
23 | return self
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/zh-Hans.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | AXWebViewController.strings
3 | AXWebViewController
4 |
5 | Created by devedbox on 16/8/14.
6 | Copyright © 2016年 AiXing. All rights reserved.
7 | */
8 | "back" = "返回";
9 | "close" = " 关闭 ";
10 | "done" = "完成";
11 | "loading" = "加载中...";
12 | "load failed" = "加载失败";
13 | "load failed:" = "网页加载失败:";
14 | "web page" = "网页由";
15 | "provided" = "提供";
16 | "browsing the web" = "内容浏览";
17 |
18 | "messages" = "来自网页的消息";
19 | "cancel" = "取消";
20 | "confirm" = "确定";
21 | "input" = "输入文字消息";
22 | "terminate" = "网页进程终止";
23 |
24 |
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | AXWebViewController.strings
3 | AXWebViewController
4 |
5 | Created by devedbox on 16/8/14.
6 | Copyright © 2016年 AiXing. All rights reserved.
7 | */
8 | "back" = "Back";
9 | "close" = " Close ";
10 | "done" = "Done";
11 | "loading" = "Loading...";
12 | "load failed" = "Load failed";
13 | "load failed:" = "Load failed: ";
14 | "web page" = "This page was generated by ";
15 | "provided" = "";
16 | "browsing the web" = "Web browsing";
17 |
18 | "messages" = "Messages from web page";
19 | "cancel" = "Cancel";
20 | "confirm" = "Confirm";
21 | "input" = "Input text content";
22 | "terminate" = "Web content process did terminate";
23 |
24 |
--------------------------------------------------------------------------------
/GTMWebKit.podspec:
--------------------------------------------------------------------------------
1 |
2 |
3 | Pod::Spec.new do |s|
4 |
5 | s.name = "GTMWebKit"
6 | s.version = "1.0.1"
7 | s.summary = "swift 针对 WKWebKit 的封装"
8 | s.swift_version= "4.2"
9 |
10 | s.homepage = "https://github.com/GTMYang/GTMWebKit"
11 |
12 | s.license = { :type => "MIT", :file => "LICENSE" }
13 | s.author = { "GTMYang" => "17757128523@163.com" }
14 |
15 |
16 | s.source = { :git => "https://github.com/GTMYang/GTMWebKit.git", :tag => s.version }
17 | s.source_files = 'GTMWebKit/*.{h,swift}'
18 | s.resources = 'GTMWebKit/GTMWebKit.bundle'
19 |
20 | s.ios.deployment_target = '8.0'
21 | s.frameworks = 'UIKit','Foundation','WebKit'
22 |
23 |
24 | end
25 |
--------------------------------------------------------------------------------
/GTMWebKit/GTMAlertable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GTMAlertable.swift
3 | // GTMWebKit
4 | //
5 | // Created by luoyang on 2017/10/26.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public protocol GTMAlertable {
12 | func alert(_ message: String)
13 | }
14 |
15 | extension GTMAlertable where Self: UIViewController {
16 | public func alert(_ message: String) {
17 | let alert = UIAlertController(title: "", message: message, preferredStyle: .alert)
18 | alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) in
19 | alert.dismiss(animated: true, completion: nil)
20 | }))
21 |
22 | self.present(alert, animated: true, completion: nil)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/GTMWebKit/WeakScriptMessageHandler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WeakScriptMessageDelegate.swift
3 | // GTMWebKit
4 | //
5 | // Created by luoyang on 2017/10/25.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import WebKit
11 |
12 | public class WeakScriptMessageHandler:NSObject, WKScriptMessageHandler {
13 | weak var realHandler: WKScriptMessageHandler?
14 |
15 | init(_ realHandler: WKScriptMessageHandler) {
16 | super.init()
17 | self.realHandler = realHandler
18 | }
19 |
20 | // MARK:- WKScriptMessageHandler
21 | public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
22 | self.realHandler?.userContentController(userContentController, didReceive: message)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GTMWebKit.swift
3 | // GTMWebKit
4 | //
5 | // Created by 骆扬 on 2018/9/11.
6 | // Copyright © 2018年 yang. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct GTMWebKitConfig {
12 | static var debug: Bool = false
13 | }
14 |
15 | func println(_ msg: String) {
16 | if GTMWebKitConfig.debug {
17 | print("GTMWebKit -----> \(msg)")
18 | }
19 | }
20 |
21 | func GTM_bundle() -> Bundle {
22 | let bundle = Bundle.init(for: GTMWebViewController.self)
23 |
24 | let resourcePath = bundle.path(forResource: "GTMWebKit", ofType: "bundle")
25 | if let path = resourcePath {
26 | let bundle2 = Bundle.init(path: path)
27 | if let bundle = bundle2 {
28 | return bundle
29 | }
30 | }
31 |
32 | return bundle
33 | }
34 |
--------------------------------------------------------------------------------
/GTMWebKit/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 | FMWK
17 | CFBundleShortVersionString
18 | 0.5
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/GTMWebKitExample/ScanViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScanViewController.swift
3 | // GTMWebKitExample
4 | //
5 | // Created by luoyang on 2017/11/2.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ScanViewController: LBXScanViewController {
12 |
13 | weak var delegate: ScanViewControllerDelegate?
14 |
15 | // MARK: - handleCodeResult
16 | /**
17 | 处理扫码结果,如果是继承本控制器的,可以重写该方法,作出相应地处理
18 | */
19 | open override func handleCodeResult(arrayResult:[LBXScanResult])
20 | {
21 | let result:LBXScanResult = arrayResult[0]
22 |
23 | print("swiftScan -> scan success: barcode = \(result.strScanned!) type = [\(String(describing: result.strBarCodeType))]")
24 | self.delegate?.onScanSuccess(barcode: result.strScanned!)
25 |
26 | // self.dismiss(animated: true, completion: nil)
27 | let _ = self.navigationController?.popViewController(animated: true)
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017年 GTMYang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/GTMWebKitExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "wk-8.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "wk-6.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "wk-7.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "wk-4.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "40x40",
29 | "idiom" : "iphone",
30 | "filename" : "wk-5.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "wk-3.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "wk-2.png",
43 | "scale" : "2x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "wk-1.png",
49 | "scale" : "3x"
50 | },
51 | {
52 | "size" : "1024x1024",
53 | "idiom" : "ios-marketing",
54 | "filename" : "wk.png",
55 | "scale" : "1x"
56 | }
57 | ],
58 | "info" : {
59 | "version" : 1,
60 | "author" : "xcode"
61 | }
62 | }
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebKit.bundle/Root.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | StringsTable
6 | Root
7 | PreferenceSpecifiers
8 |
9 |
10 | Type
11 | PSGroupSpecifier
12 | Title
13 | Group
14 |
15 |
16 | Type
17 | PSTextFieldSpecifier
18 | Title
19 | Name
20 | Key
21 | name_preference
22 | DefaultValue
23 |
24 | IsSecure
25 |
26 | KeyboardType
27 | Alphabet
28 | AutocapitalizationType
29 | None
30 | AutocorrectionType
31 | No
32 |
33 |
34 | Type
35 | PSToggleSwitchSpecifier
36 | Title
37 | Enabled
38 | Key
39 | enabled_preference
40 | DefaultValue
41 |
42 |
43 |
44 | Type
45 | PSSliderSpecifier
46 | Key
47 | slider_preference
48 | DefaultValue
49 | 0.5
50 | MinimumValue
51 | 0
52 | MaximumValue
53 | 1
54 | MinimumValueImage
55 |
56 | MaximumValueImage
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebViewCookies.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GTMWebViewCookies.swift
3 | // GTMWebKit
4 | //
5 | // Created by luoyang on 2017/11/16.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 |
12 | public class GTMWebViewCookies: NSObject {
13 |
14 | /// 将 HTTPCookieStorage 中的 Cookies 同步到 WKWebsiteDataStore 中
15 | public static func shareNativeCookies(url: URLConvertible) {
16 | if let _url = url.url() {
17 | if #available(iOS 11.0, *) {
18 | let cookiesStorage = HTTPCookieStorage.shared
19 | let cookies = cookiesStorage.cookies(for: _url)
20 | let selfCookies = cookies!.filter({ (cookie) -> Bool in
21 | return cookie.domain == _url.host
22 | })
23 |
24 | let dataStore = WKWebsiteDataStore.default()
25 | for cookie in selfCookies {
26 | dataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
27 | }
28 |
29 | }
30 | }
31 | }
32 | /// 将 WKWebsiteDataStore 中的 Cookies 同步到 HTTPCookieStorage 中
33 | public static func shareWebViewCookies(url: URLConvertible) {
34 | if let _url = url.url() {
35 | if #available(iOS 11.0, *) {
36 | let dataStore = WKWebsiteDataStore.default()
37 | dataStore.httpCookieStore.getAllCookies({ (cookies) in
38 | let selfCookies = cookies.filter({ (cookie) -> Bool in
39 | return cookie.domain == _url.host
40 | })
41 | let cookiesStorage = HTTPCookieStorage.shared
42 | for cookie in selfCookies {
43 | cookiesStorage.setCookie(cookie)
44 | }
45 | })
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/GTMWebKitExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | WebKit例子
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0.1
21 | CFBundleVersion
22 | 1.0.1
23 | LSRequiresIPhoneOS
24 |
25 | NSAppTransportSecurity
26 |
27 | NSAllowsArbitraryLoads
28 |
29 | NSAllowsArbitraryLoadsInWebContent
30 |
31 |
32 | NSCameraUsageDescription
33 | 请点击“允许”以允许访问
34 | UILaunchStoryboardName
35 | LaunchScreen
36 | UIMainStoryboardFile
37 | Main
38 | UIRequiredDeviceCapabilities
39 |
40 | armv7
41 |
42 | UISupportedInterfaceOrientations
43 |
44 | UIInterfaceOrientationLandscapeLeft
45 | UIInterfaceOrientationPortrait
46 | UIInterfaceOrientationPortraitUpsideDown
47 | UIInterfaceOrientationLandscapeRight
48 |
49 | UISupportedInterfaceOrientations~ipad
50 |
51 | UIInterfaceOrientationPortrait
52 | UIInterfaceOrientationPortraitUpsideDown
53 | UIInterfaceOrientationLandscapeLeft
54 | UIInterfaceOrientationLandscapeRight
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/GTMWebKitExample/BarcodeScanable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BarcodeScanable.swift
3 | // Olliix
4 | //
5 | // Created by luoyang on 2017/9/6.
6 | // Copyright © 2017年 syncsoft. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol ScanViewControllerDelegate: class {
12 | func onScanSuccess(barcode: String)
13 | }
14 |
15 | protocol BarcodeScanable: ScanViewControllerDelegate {
16 | func startScanBarcode(viewTitle: String)
17 | }
18 |
19 | extension BarcodeScanable where Self: UIViewController {
20 |
21 | /// 扫描方法
22 | func startScanBarcode(viewTitle: String) {
23 | //设置扫码区域参数
24 | var style = LBXScanViewStyle()
25 |
26 | style.centerUpOffset = 44
27 | style.photoframeAngleStyle = LBXScanViewPhotoframeAngleStyle.Inner
28 | style.photoframeLineW = 4
29 | style.photoframeAngleW = 28
30 | style.photoframeAngleH = 16
31 | style.isNeedShowRetangle = false
32 |
33 | style.anmiationStyle = LBXScanViewAnimationStyle.LineStill
34 |
35 |
36 | style.animationImage = createImageWithColor(color: UIColor.red)
37 | //非正方形
38 | //设置矩形宽高比
39 | style.whRatio = 4.3/2.18
40 |
41 | //离左边和右边距离
42 | style.xScanRetangleOffset = 30
43 |
44 | let scanViewController = ScanViewController()
45 | scanViewController.title = viewTitle
46 |
47 | scanViewController.delegate = self
48 |
49 | scanViewController.scanStyle = style
50 |
51 | self.navigationController?.pushViewController(scanViewController, animated: false)
52 | }
53 |
54 | private func createImageWithColor(color:UIColor)->UIImage {
55 | let rect=CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0)
56 | UIGraphicsBeginImageContext(rect.size)
57 | let context = UIGraphicsGetCurrentContext()
58 | context!.setFillColor(color.cgColor)
59 | context!.fill(rect)
60 | let theImage = UIGraphicsGetImageFromCurrentImageContext()
61 | UIGraphicsEndImageContext()
62 | return theImage!
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebView+Alert.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GTMWebViewAlert.swift
3 | // GTMWebKit
4 | //
5 | // Created by luoyang on 2017/10/25.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 |
12 | extension GTMWebViewController: WKUIDelegate {
13 |
14 | open func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
15 | let alert = UIAlertController(title: "", message: message, preferredStyle: .alert)
16 | alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) in
17 | completionHandler()
18 | }))
19 |
20 | self.present(alert, animated: false, completion: nil)
21 | }
22 |
23 | open func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
24 | let alert = UIAlertController(title: "", message: message, preferredStyle: .alert)
25 | alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) in
26 | completionHandler(true)
27 | }))
28 | alert.addAction(UIAlertAction(title: "Cancle", style: .cancel, handler: { (_) in
29 | completionHandler(false)
30 | }))
31 | self.present(alert, animated: false, completion: nil)
32 | }
33 |
34 | open func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
35 |
36 | let alert = UIAlertController(title: prompt, message: defaultText, preferredStyle: .alert)
37 | alert.addTextField { (textFiled) in
38 | textFiled.textColor = .red
39 | }
40 | alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) in
41 | completionHandler(alert.textFields![0].text!)
42 | }))
43 | self.present(alert, animated: false, completion: nil)
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/GTMWebKitExample/Swift Scan/LBXScanNetAnimation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LBXScanNetAnimation.swift
3 | // swiftScan
4 | //
5 | // Created by lbxia on 15/12/9.
6 | // Copyright © 2015年 xialibing. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class LBXScanNetAnimation: UIImageView {
12 |
13 | var isAnimationing = false
14 | var animationRect:CGRect = CGRect.zero
15 |
16 |
17 |
18 | static public func instance()->LBXScanNetAnimation
19 | {
20 | return LBXScanNetAnimation()
21 | }
22 |
23 | func startAnimatingWithRect(animationRect:CGRect, parentView:UIView, image:UIImage?)
24 | {
25 | self.image = image
26 | self.animationRect = animationRect
27 | parentView.addSubview(self)
28 |
29 | self.isHidden = false;
30 |
31 | isAnimationing = true;
32 |
33 | if (image != nil)
34 | {
35 | stepAnimation()
36 | }
37 |
38 |
39 |
40 | }
41 |
42 | @objc func stepAnimation()
43 | {
44 | if (!isAnimationing) {
45 | return;
46 | }
47 |
48 | var frame = animationRect;
49 |
50 |
51 | let hImg = self.image!.size.height * animationRect.size.width / self.image!.size.width;
52 |
53 | frame.origin.y -= hImg;
54 | frame.size.height = hImg;
55 | self.frame = frame;
56 |
57 | self.alpha = 0.0;
58 |
59 | UIView.animate(withDuration: 1.2, animations: { () -> Void in
60 |
61 | self.alpha = 1.0;
62 |
63 | var frame = self.animationRect;
64 | let hImg = self.image!.size.height * self.animationRect.size.width / self.image!.size.width;
65 |
66 | frame.origin.y += (frame.size.height - hImg);
67 | frame.size.height = hImg;
68 |
69 | self.frame = frame;
70 |
71 | }, completion:{ (value: Bool) -> Void in
72 |
73 | self.perform(#selector(LBXScanNetAnimation.stepAnimation), with: nil, afterDelay: 0.3)
74 |
75 | })
76 |
77 | }
78 |
79 | func stopStepAnimating()
80 | {
81 | self.isHidden = true;
82 | isAnimationing = false;
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/GTMWebKitExample/Swift Scan/LBXPermissions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LBXPermissions.swift
3 | // swiftScan
4 | //
5 | // Created by xialibing on 15/12/15.
6 | // Copyright © 2015年 xialibing. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import AVFoundation
11 | import Photos
12 | import AssetsLibrary
13 |
14 |
15 |
16 | class LBXPermissions: NSObject {
17 |
18 | //MARK: ----获取相册权限
19 | static func authorizePhotoWith(comletion:@escaping (Bool)->Void )
20 | {
21 | let granted = PHPhotoLibrary.authorizationStatus()
22 | switch granted {
23 | case PHAuthorizationStatus.authorized:
24 | comletion(true)
25 | case PHAuthorizationStatus.denied,PHAuthorizationStatus.restricted:
26 | comletion(false)
27 | case PHAuthorizationStatus.notDetermined:
28 | PHPhotoLibrary.requestAuthorization({ (status) in
29 | comletion(status == PHAuthorizationStatus.authorized ? true:false)
30 | })
31 | }
32 |
33 | }
34 |
35 | //MARK: ---相机权限
36 | static func authorizeCameraWith(comletion:@escaping (Bool)->Void )
37 | {
38 | let granted = AVCaptureDevice.authorizationStatus(for: AVMediaType.video);
39 |
40 | switch granted {
41 | case AVAuthorizationStatus.authorized:
42 | comletion(true)
43 | break;
44 | case AVAuthorizationStatus.denied:
45 | comletion(false)
46 | break;
47 | case AVAuthorizationStatus.restricted:
48 | comletion(false)
49 | break;
50 | case AVAuthorizationStatus.notDetermined:
51 |
52 | AVCaptureDevice.requestAccess(for: AVMediaType.video, completionHandler: { (granted:Bool) in
53 | comletion(granted)
54 | })
55 | }
56 | }
57 |
58 | //MARK:跳转到APP系统设置权限界面
59 | static func jumpToSystemPrivacySetting()
60 | {
61 | let appSetting = URL(string:UIApplication.openSettingsURLString)
62 |
63 | if appSetting != nil
64 | {
65 | if #available(iOS 10, *) {
66 | UIApplication.shared.open(appSetting!, options: [:], completionHandler: nil)
67 | }
68 | else{
69 | UIApplication.shared.openURL(appSetting!)
70 | }
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/GTMWebKitExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // GTMWebKitExample
4 | //
5 | // Created by luoyang on 2017/10/25.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | UINavigationBar.appearance().tintColor = UIColor.gray
20 |
21 |
22 | return true
23 | }
24 |
25 | func applicationWillResignActive(_ application: UIApplication) {
26 | // 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.
27 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
28 | }
29 |
30 | func applicationDidEnterBackground(_ application: UIApplication) {
31 | // 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.
32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
33 | }
34 |
35 | func applicationWillEnterForeground(_ application: UIApplication) {
36 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
37 | }
38 |
39 | func applicationDidBecomeActive(_ application: UIApplication) {
40 | // 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.
41 | }
42 |
43 | func applicationWillTerminate(_ application: UIApplication) {
44 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
45 | }
46 |
47 |
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/GTMWebKitExample/Swift Scan/LBXScanLineAnimation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LBXScanLineAnimation.swift
3 | // swiftScan
4 | //
5 | // Created by lbxia on 15/12/9.
6 | // Copyright © 2015年 xialibing. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class LBXScanLineAnimation: UIImageView {
12 |
13 | var isAnimationing = false
14 | var animationRect: CGRect = CGRect.zero
15 |
16 | func startAnimatingWithRect(animationRect: CGRect, parentView: UIView, image: UIImage?)
17 | {
18 | self.image = image
19 | self.animationRect = animationRect
20 | parentView.addSubview(self)
21 |
22 | self.isHidden = false;
23 |
24 | isAnimationing = true;
25 |
26 | if image != nil
27 | {
28 | stepAnimation()
29 | }
30 |
31 | }
32 |
33 | @objc func stepAnimation()
34 | {
35 | if (!isAnimationing) {
36 | return;
37 | }
38 |
39 | var frame:CGRect = animationRect;
40 |
41 | let hImg = self.image!.size.height * animationRect.size.width / self.image!.size.width;
42 |
43 | frame.origin.y -= hImg;
44 | frame.size.height = hImg;
45 | self.frame = frame;
46 | self.alpha = 0.0;
47 |
48 | UIView.animate(withDuration: 1.4, animations: { () -> Void in
49 |
50 | self.alpha = 1.0;
51 |
52 | var frame = self.animationRect;
53 | let hImg = self.image!.size.height * self.animationRect.size.width / self.image!.size.width;
54 |
55 | frame.origin.y += (frame.size.height - hImg);
56 | frame.size.height = hImg;
57 |
58 | self.frame = frame;
59 |
60 | }, completion:{ (value: Bool) -> Void in
61 |
62 | self.perform(#selector(LBXScanLineAnimation.stepAnimation), with: nil, afterDelay: 0.3)
63 | })
64 |
65 | }
66 |
67 | func stopStepAnimating()
68 | {
69 | self.isHidden = true;
70 | isAnimationing = false;
71 | }
72 |
73 | static public func instance()->LBXScanLineAnimation
74 | {
75 | return LBXScanLineAnimation()
76 | }
77 |
78 | deinit
79 | {
80 | // print("LBXScanLineAnimation deinit")
81 | stopStepAnimating()
82 | }
83 |
84 | }
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/GTMWebKitExample/Swift Scan/LBXScanViewStyle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LBXScanViewStyle.swift
3 | // swiftScan
4 | //
5 | // Created by xialibing on 15/12/8.
6 | // Copyright © 2015年 xialibing. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | ///扫码区域动画效果
12 | public enum LBXScanViewAnimationStyle
13 | {
14 | case LineMove //线条上下移动
15 | case NetGrid//网格
16 | case LineStill//线条停止在扫码区域中央
17 | case None //无动画
18 | }
19 |
20 | ///扫码区域4个角位置类型
21 | public enum LBXScanViewPhotoframeAngleStyle
22 | {
23 | case Inner//内嵌,一般不显示矩形框情况下
24 | case Outer//外嵌,包围在矩形框的4个角
25 | case On //在矩形框的4个角上,覆盖
26 | }
27 |
28 |
29 | public struct LBXScanViewStyle
30 | {
31 |
32 | // MARK: - -中心位置矩形框
33 |
34 | /// 是否需要绘制扫码矩形框,默认YES
35 | public var isNeedShowRetangle:Bool = true
36 |
37 | /**
38 | * 默认扫码区域为正方形,如果扫码区域不是正方形,设置宽高比
39 | */
40 | public var whRatio:CGFloat = 1.0
41 |
42 | /**
43 | @brief 矩形框(视频显示透明区)域向上移动偏移量,0表示扫码透明区域在当前视图中心位置,如果负值表示扫码区域下移
44 | */
45 | public var centerUpOffset:CGFloat = 44
46 |
47 | /**
48 | * 矩形框(视频显示透明区)域离界面左边及右边距离,默认60
49 | */
50 | public var xScanRetangleOffset:CGFloat = 60
51 |
52 | /**
53 | @brief 矩形框线条颜色,默认白色
54 | */
55 | public var colorRetangleLine = UIColor.white
56 |
57 |
58 | //MARK -矩形框(扫码区域)周围4个角
59 |
60 | /**
61 | @brief 扫码区域的4个角类型
62 | */
63 | public var photoframeAngleStyle = LBXScanViewPhotoframeAngleStyle.Outer
64 |
65 | //4个角的颜色
66 | public var colorAngle = UIColor(red: 0.0, green: 167.0/255.0, blue: 231.0/255.0, alpha: 1.0)
67 |
68 | //扫码区域4个角的宽度和高度
69 | public var photoframeAngleW:CGFloat = 24.0
70 | public var photoframeAngleH:CGFloat = 24.0
71 | /**
72 | @brief 扫码区域4个角的线条宽度,默认6,建议8到4之间
73 | */
74 | public var photoframeLineW:CGFloat = 6
75 |
76 | //MARK: ----动画效果
77 |
78 | /**
79 | @brief 扫码动画效果:线条或网格
80 | */
81 | public var anmiationStyle = LBXScanViewAnimationStyle.LineMove
82 |
83 |
84 | /**
85 | * 动画效果的图像,如线条或网格的图像
86 | */
87 | public var animationImage:UIImage?
88 |
89 |
90 | // MARK: -非识别区域颜色,默认 RGBA (0,0,0,0.5),范围(0--1)
91 | public var color_NotRecoginitonArea:UIColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.5);
92 |
93 | public init()
94 | {
95 |
96 | }
97 |
98 |
99 | }
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebControls.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GTMWebControls.swift
3 | // GTMWebKit
4 | //
5 | // Created by 骆扬 on 2018/11/8.
6 | // Copyright © 2018 yang. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public protocol GTMWebErrorViewReloadHandler {
12 | /// 自定义View 可以通过此 block 刷新页面
13 | var reloadHandler: ()->Void { get set }
14 | }
15 |
16 | public typealias GTMWebErrorView = UIView & GTMWebErrorViewReloadHandler
17 |
18 | class GTMWebNetErrorView: GTMWebErrorView {
19 | var reloadHandler: () -> Void = {}
20 | private var iconName: String?
21 | private var iconImageV: UIImageView!
22 | private var reloadButton: UIButton!
23 |
24 | convenience init(_ iconName: String) {
25 | let size = UIScreen.main.bounds.size
26 | self.init(frame: CGRect.init(x: (size.width - 320)/2, y: (size.height - 200)/2 - 64, width: 320, height: 200))
27 | self.iconName = iconName
28 | setup()
29 | }
30 |
31 | private override init(frame: CGRect) {
32 | super.init(frame: frame)
33 | }
34 | required init?(coder aDecoder: NSCoder) {
35 | super.init(coder: aDecoder)
36 | }
37 |
38 | func setup() {
39 | // icon
40 | let icon = UIImageView()
41 | let iconImage = UIImage.init(named: iconName ?? "", in: GTM_bundle(), compatibleWith: nil)
42 | icon.image = iconImage
43 | icon.sizeToFit()
44 | self.iconImageV = icon
45 | self.addSubview(iconImageV)
46 | // button
47 | let button = UIButton(type: .custom)
48 | button.setTitle("重新加载", for: .normal)
49 | button.setTitleColor(.gray, for: .normal)
50 | button.sizeToFit()
51 | button.addTarget(self, action: #selector(onReload), for: .touchUpInside)
52 | button.layer.borderColor = UIColor.lightGray.cgColor
53 | button.layer.borderWidth = 1
54 | button.layer.cornerRadius = 2
55 | self.reloadButton = button
56 | self.addSubview(reloadButton)
57 | }
58 |
59 | // MARK: - Event
60 | @objc func onReload() {
61 | self.reloadHandler()
62 | }
63 |
64 | // MARK: - Layout
65 | override func layoutSubviews() {
66 | super.layoutSubviews()
67 | let frame = self.bounds
68 | var y: CGFloat = 0
69 | if var size = iconImageV.image?.size {
70 | iconImageV.frame = CGRect(x: (frame.size.width - size.width)/2, y: y, width: size.width, height: size.height)
71 | y = size.height + 30
72 | size = CGSize.init(width: 200, height: 40)
73 | reloadButton.frame = CGRect(x: (frame.size.width - size.width)/2, y: y, width: size.width, height: size.height)
74 | }
75 |
76 | }
77 |
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | GTMWebKit
16 | ===================
17 | `GTMWebKit` swift 针对 WKWebView 的封装
18 |
19 | # Introduction
20 |
21 | - 使得在App内嵌网页变得非常简单
22 | - 实现了类似微信里面的网页导航控制功能
23 | - 注册JS使用的API方法变得简单
24 | - 支持Swift4
25 | - 支持与原生代码共享Cookies
26 |
27 |
28 |
29 | # Demo
30 | 直接下载代码,里面详细的使用例子
31 |
32 | # Installation
33 |
34 | ## Cocoapods
35 |
36 | Install Cocoapods if need be.
37 |
38 | ```bash
39 | $ gem install cocoapods
40 | ```
41 |
42 | Add `GTMWebKit` in your `Podfile`.
43 |
44 | ```ruby
45 | use_frameworks!
46 |
47 | pod 'GTMWebKit'
48 | ```
49 |
50 | Then, run the following command.
51 |
52 | ```bash
53 | $ pod install
54 | ```
55 |
56 |
57 | ## Manual
58 |
59 | Copy `GTMWebKit` folder to your project. That's it.
60 |
61 | _**Note:** Make sure that all files in `GTMWebKit` included in Compile Sources in Build Phases._
62 |
63 | # 版本
64 |
65 | ## Vesrion 1.0
66 |
67 | This version requires Xcode 9.0 and Swift 4.2.
68 |
69 | # 使用帮助
70 |
71 | Firstly, import `GTMWebKit`.
72 |
73 | ```swift
74 | import GTMWebKit
75 | ```
76 |
77 | ## Push方式内嵌网页
78 | ```swift
79 | // Push
80 | let webVC = GTMWebViewController.init(with: "https://www.baidu.com", navigType: .navbar)
81 | self.navigationController?.pushViewController(webVC, animated: true)
82 | ```
83 |
84 | ## Present方式内嵌网页
85 | ```swift
86 | let webVC = GTMWebViewController.init(with: "https://www.baidu.com", navigType: .toolbar)
87 | let navigationC = UINavigationController.init(rootViewController: webVC)
88 | navigationC.navigationBar.tintColor = UIColor.gray
89 | self.present(navigationC, animated: true, completion: nil)
90 | ```
91 |
92 | ## 配置项
93 |
94 | ```swift
95 | public enum GTMWK_NavigationType {
96 | case navbar // web导航控制按钮放在导航栏
97 | case toolbar // web导航控制按钮放在底部工具栏
98 | case both // 同时使用两种导航按钮
99 | case none // 不使用web导航按钮
100 | }
101 |
102 | public var navigType: GTMWK_NavigationType! // 控制网页导航的方式(导航栏,工具栏)
103 | public var isShowCloseItem = true // 是否显示关闭按钮(navigType == .navbar 时使用)
104 | public var isShowToolbar = true // 是否显示工具栏(navigType == .toolbar 时使用)
105 | public var isForcedUIWebView = false // 强制使用 UIWebView
106 | public var isNeedShareCookies = false // 是否需要共享cookies
107 | public var backIconName: String? // 返回按钮图标,可自行设置
108 | public var view404: GTMWebErrorView! // 资源不存在的时候展示的UI,可自定义
109 | public var netErrorView: GTMWebErrorView! // 网络错误的时候展示的UI,可自定义
110 |
111 | ```
112 |
113 |
114 |
115 | #参与开源
116 | 欢迎提交 issue 和 PR,大门永远向所有人敞开。
117 |
118 | #开源协议
119 | 本项目遵循 MIT 协议开源,具体请查看根目录下的 [LICENSE](https://raw.githubusercontent.com/GTMYang/GTMWebKit/master/LICENSE) 文件。
120 |
121 |
122 |
--------------------------------------------------------------------------------
/GTMWebKitExample/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | iOS and Js
7 |
15 |
16 |
17 |
18 |
19 |
20 |
Test how to use swift call js
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/GTMWebKitExample/CustomWebViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CustomWebViewController.swift
3 | // GTMWebKitExample
4 | //
5 | // Created by luoyang on 2017/11/1.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import GTMWebKit
11 | import WebKit
12 |
13 | class CustomWebViewController: GTMWebViewController {
14 |
15 | var lblJsMessage: UILabel!
16 | var btnCallJsMethod: UIButton!
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 |
21 | self.setup()
22 | self.registApiForJs()
23 | }
24 |
25 | func setup() {
26 | self.title = "Native code <-> JS"
27 |
28 | let screenSize = UIScreen.main.bounds
29 | // message label
30 | self.lblJsMessage = UILabel()
31 | lblJsMessage.frame = CGRect.init(x: 0, y: 64, width: screenSize.width, height: 100)
32 | lblJsMessage.textAlignment = .center
33 | lblJsMessage.backgroundColor = .orange
34 | lblJsMessage.isHidden = true
35 | self.view.addSubview(self.lblJsMessage)
36 | // button
37 | self.btnCallJsMethod = UIButton.init(type: .custom)
38 | btnCallJsMethod.frame = CGRect.init(x: 8, y: screenSize.height - 122, width: screenSize.width - 16 , height: 50)
39 | btnCallJsMethod.setTitle("Swift 调用 JS 方法改变网页中控件颜色", for: .normal)
40 | btnCallJsMethod.setTitleColor(.black, for: .normal)
41 | btnCallJsMethod.backgroundColor = .white
42 | btnCallJsMethod.layer.borderColor = UIColor.gray.cgColor
43 | btnCallJsMethod.layer.borderWidth = 1
44 | btnCallJsMethod.addTarget(self, action: #selector(onCallJsMethod), for: .touchUpInside)
45 | self.view.addSubview(self.btnCallJsMethod)
46 | }
47 |
48 | override func webDidLoad() {
49 | super.webDidLoad()
50 | self.wkWebView?.evaluateJavaScript("jsinit();", completionHandler: { (data, error) in
51 | if let _ = error {
52 | print("error: javascript 'jsinit()' method is undifind!")
53 | }
54 | })
55 | }
56 |
57 | func registApiForJs() {
58 |
59 | // 简单测试方法
60 | self.registApi(method: "test") { [weak self] (body) in
61 | print("\nCustomWebViewController -----> recived js message: \(body ?? "")\n\n")
62 | let message = "\(body ?? "")"
63 | self?.showMessage(message: message)
64 | }
65 | // 扫描功能API
66 | self.registApi(method: "scanBarcode") { [weak self] (body) in
67 | self?.startScanBarcode(viewTitle: "条码扫描")
68 | }
69 |
70 | }
71 |
72 | // MARK: - Events
73 | @objc func onCallJsMethod() {
74 | let wkwebV = self.webView
75 | wkwebV?.evaluateJavaScript("changeColor();", completionHandler: nil)
76 | }
77 |
78 | // MARK: - Private
79 | fileprivate func showMessage(message: String) {
80 | self.lblJsMessage.text = message
81 |
82 | DispatchQueue.main.async {
83 | self.lblJsMessage.isHidden = false
84 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3, execute: {
85 | self.lblJsMessage.isHidden = true
86 | })
87 | }
88 | }
89 |
90 | }
91 |
92 | extension CustomWebViewController: ScanViewControllerDelegate, BarcodeScanable {
93 |
94 | // MARK: - ScanViewControllerDelegate
95 | func onScanSuccess(barcode: String) {
96 | let message = "条码内容为:\(barcode)"
97 | self.showMessage(message: message)
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/GTMWebKitExample/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // GTMWebKitExample
4 | //
5 | // Created by luoyang on 2017/10/25.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import GTMWebKit
11 |
12 | class ViewController: UITableViewController {
13 |
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 | // Do any additional setup after loading the view, typically from a nib.
17 | self.navigationController?.navigationBar.backIndicatorImage = UIImage(named: "nav_back")
18 | }
19 |
20 | override func didReceiveMemoryWarning() {
21 | super.didReceiveMemoryWarning()
22 | // Dispose of any resources that can be recreated.
23 | }
24 |
25 | // MARK: - Table View
26 |
27 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
28 | if indexPath.row == 0 {
29 | // Push
30 | let webVC = GTMWebViewController.init(with: "https://www.baidu.com", navigType: .navbar)
31 | self.navigationController?.pushViewController(webVC, animated: true)
32 | } else if indexPath.row == 1 {
33 | // Present
34 | let webVC = GTMWebViewController.init(with: "https://www.baidu.com", navigType: .toolbar)
35 | let navigationC = UINavigationController.init(rootViewController: webVC)
36 | navigationC.navigationBar.tintColor = UIColor.gray
37 | self.present(navigationC, animated: true, completion: nil)
38 | } else if indexPath.row == 2 {
39 | // Github
40 | let webVC = GTMWebViewController.init(with: "https://www.baidu.com", navigType: .both)
41 | self.navigationController?.pushViewController(webVC, animated: true)
42 | } else if indexPath.row == 3 {
43 | // Github
44 | let webVC = GTMWebViewController.init(with: "https://www.baidu.com", navigType: .none)
45 | self.navigationController?.pushViewController(webVC, animated: true)
46 | } else if indexPath.row == 4 {
47 | // Github
48 | let webVC = GTMWebViewController.init(with: "https://github.com", navigType: .navbar)
49 | webVC.isShowCloseItem = false
50 | self.navigationController?.pushViewController(webVC, animated: true)
51 | } else if indexPath.row == 5 {
52 | // WKWebView Native <-> JS
53 | let url = Bundle.main.url(forResource: "test", withExtension: "html")
54 | let webVC = CustomWebViewController.init(with: url!, navigType: .navbar)
55 | self.navigationController?.pushViewController(webVC, animated: true)
56 | } else if indexPath.row == 6 {
57 | // WKWebView Cookies
58 | let webVC = WKWebViewCookiesVC.init(with: cookieTestUrl, navigType: .navbar)
59 | webVC.isShowCloseItem = false
60 | webVC.isShowToolbar = false
61 | webVC.isNeedShareCookies = true
62 |
63 | self.navigationController?.pushViewController(webVC, animated: true)
64 | } else if indexPath.row == 7 {
65 | // 404
66 | let webVC = GTMWebViewController.init(with: "https://www.baidu1.com", navigType: .navbar)
67 | self.navigationController?.pushViewController(webVC, animated: true)
68 | } else if indexPath.row == 8 {
69 | // back icon
70 | let webVC = GTMWebViewController.init(with: "https://www.baidu.com", navigType: .navbar)
71 | webVC.backIconName = "cus_back"
72 | self.navigationController?.pushViewController(webVC, animated: true)
73 | }
74 | }
75 |
76 | var cookieTestUrl = "http://192.168.85.168" //"https://www.baidu.com" //
77 |
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/GTMWebKitExample/UIWebViewCookiesVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIWebViewCookiesVC.swift
3 | // GTMWebKitExample
4 | //
5 | // Created by luoyang on 2017/11/16.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 | import GTMWebKit
12 |
13 | class UIWebViewCookiesVC: GTMWebViewController {
14 |
15 | var lblCookies: UILabel!
16 | var btnShowCookies: UIButton!
17 | var btnShowNativeCookies: UIButton!
18 |
19 | override func viewDidLoad() {
20 | super.viewDidLoad()
21 |
22 | self.setup()
23 | }
24 | func setup() {
25 | self.title = "UIWebView Cookies"
26 |
27 | let screenSize = UIScreen.main.bounds
28 | // message label
29 | self.lblCookies = UILabel()
30 | lblCookies.frame = CGRect.init(x: 20, y: 84, width: screenSize.width - 40, height: 300)
31 | lblCookies.textAlignment = .left
32 | lblCookies.backgroundColor = .orange
33 | lblCookies.numberOfLines = 0
34 | lblCookies.isHidden = true
35 | self.view.addSubview(self.lblCookies)
36 | // button web cookies
37 | self.btnShowCookies = UIButton.init(type: .custom)
38 | btnShowCookies.frame = CGRect.init(x: 8, y: screenSize.height - 122, width: screenSize.width - 16 , height: 50)
39 | btnShowCookies.setTitle("WKWebsiteDataStore Cookies", for: .normal)
40 | btnShowCookies.setTitleColor(.white, for: .normal)
41 | btnShowCookies.backgroundColor = .gray
42 | btnShowCookies.layer.borderColor = UIColor.gray.cgColor
43 | btnShowCookies.layer.borderWidth = 1
44 | btnShowCookies.addTarget(self, action: #selector(onCallCookies), for: .touchUpInside)
45 | self.view.addSubview(self.btnShowCookies)
46 | // button native cookies
47 | self.btnShowNativeCookies = UIButton.init(type: .custom)
48 | btnShowNativeCookies.frame = CGRect.init(x: 8, y: screenSize.height - 180, width: screenSize.width - 16 , height: 50)
49 | btnShowNativeCookies.setTitle("HTTPCookieStorage Cookies", for: .normal)
50 | btnShowNativeCookies.setTitleColor(.white, for: .normal)
51 | btnShowNativeCookies.backgroundColor = .gray
52 | btnShowNativeCookies.layer.borderColor = UIColor.gray.cgColor
53 | btnShowNativeCookies.layer.borderWidth = 1
54 | btnShowNativeCookies.addTarget(self, action: #selector(onCallNativeCookies), for: .touchUpInside)
55 | self.view.addSubview(self.btnShowNativeCookies)
56 | }
57 |
58 | // MARK: - Events
59 |
60 | @objc func onCallCookies() {
61 | // WKWebView 获取Cookies
62 | if #available(iOS 11.0, *) {
63 | let dataStore = WKWebsiteDataStore.default()
64 | // let dataStore = self.wkWebView?.configuration.websiteDataStore
65 | dataStore.httpCookieStore.getAllCookies({ (cookies) in
66 | let selfCookies = cookies.filter({ (cookie) -> Bool in
67 | return cookie.domain == self.webView!.url!.host
68 | })
69 | self.showCookies(selfCookies)
70 | })
71 | }
72 | }
73 |
74 | @objc func onCallNativeCookies() {
75 | // UIWebView 获取Cookies
76 | let cookiesStorage = HTTPCookieStorage.shared
77 | let cookies = cookiesStorage.cookies(for: webView.url!)
78 |
79 | let selfCookies = cookies!.filter({ (cookie) -> Bool in
80 | return cookie.domain == self.webView!.url!.host
81 | })
82 |
83 | self.showCookies(selfCookies)
84 | }
85 |
86 |
87 |
88 | // MARK: - Private
89 | fileprivate func showCookies(_ cookies: [HTTPCookie]) {
90 | let cookiesString = cookies.reduce("", { (re, cookie) -> String in
91 | return re + " \(cookie.name): \(cookie.value)\n"
92 | })
93 | self.lblCookies.text = cookiesString
94 |
95 | DispatchQueue.main.async {
96 | self.lblCookies.isHidden = false
97 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 15, execute: {
98 | self.lblCookies.isHidden = true
99 | })
100 | }
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/GTMWebKitExample/WKWebViewCookiesVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WKWebViewCookiesVC.swift
3 | // GTMWebKitExample
4 | //
5 | // Created by luoyang on 2017/11/16.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 | import GTMWebKit
12 |
13 | class WKWebViewCookiesVC: GTMWebViewController {
14 |
15 | var lblCookies: UILabel!
16 | var btnShowCookies: UIButton!
17 | var btnShowNativeCookies: UIButton!
18 |
19 | override func viewDidLoad() {
20 | super.viewDidLoad()
21 |
22 | self.setup()
23 | }
24 |
25 | func setup() {
26 | self.title = "WKWebView Cookies"
27 |
28 | let screenSize = UIScreen.main.bounds
29 | // message label
30 | self.lblCookies = UILabel()
31 | lblCookies.frame = CGRect.init(x: 20, y: 84, width: screenSize.width - 40, height: 300)
32 | lblCookies.textAlignment = .left
33 | lblCookies.backgroundColor = .orange
34 | lblCookies.numberOfLines = 0
35 | lblCookies.isHidden = true
36 | self.view.addSubview(self.lblCookies)
37 | // button web cookies
38 | self.btnShowCookies = UIButton.init(type: .custom)
39 | btnShowCookies.frame = CGRect.init(x: 8, y: screenSize.height - 122, width: screenSize.width - 16 , height: 50)
40 | btnShowCookies.setTitle("WKWebsiteDataStore Cookies", for: .normal)
41 | btnShowCookies.setTitleColor(.white, for: .normal)
42 | btnShowCookies.backgroundColor = .gray
43 | btnShowCookies.layer.borderColor = UIColor.gray.cgColor
44 | btnShowCookies.layer.borderWidth = 1
45 | btnShowCookies.addTarget(self, action: #selector(onCallCookies), for: .touchUpInside)
46 | self.view.addSubview(self.btnShowCookies)
47 | // button native cookies
48 | self.btnShowNativeCookies = UIButton.init(type: .custom)
49 | btnShowNativeCookies.frame = CGRect.init(x: 8, y: screenSize.height - 180, width: screenSize.width - 16 , height: 50)
50 | btnShowNativeCookies.setTitle("HTTPCookieStorage Cookies", for: .normal)
51 | btnShowNativeCookies.setTitleColor(.white, for: .normal)
52 | btnShowNativeCookies.backgroundColor = .gray
53 | btnShowNativeCookies.layer.borderColor = UIColor.gray.cgColor
54 | btnShowNativeCookies.layer.borderWidth = 1
55 | btnShowNativeCookies.addTarget(self, action: #selector(onCallNativeCookies), for: .touchUpInside)
56 | self.view.addSubview(self.btnShowNativeCookies)
57 | }
58 | //
59 | // override func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
60 | //
61 | // super.webView(webView, decidePolicyFor: navigationResponse, decisionHandler: decisionHandler)
62 | //
63 | // guard #available(iOS 11.0, *) else {
64 | // if let response = navigationResponse.response as? HTTPURLResponse {
65 | // let cookies = HTTPCookie.cookies(withResponseHeaderFields: response.allHeaderFields as! [String : String], for: response.url!)
66 | // self.showCookies(cookies)
67 | // }
68 | // return
69 | // }
70 | // }
71 |
72 | // MARK: - Events
73 |
74 | @objc func onCallCookies() {
75 | // WKWebView 获取Cookies
76 | if #available(iOS 11.0, *) {
77 | let dataStore = WKWebsiteDataStore.default()
78 | // let dataStore = self.wkWebView?.configuration.websiteDataStore
79 | dataStore.httpCookieStore.getAllCookies({ (cookies) in
80 | let selfCookies = cookies.filter({ (cookie) -> Bool in
81 | return cookie.domain == self.webView!.url!.host
82 | })
83 | self.showCookies(selfCookies)
84 | })
85 | }
86 | }
87 |
88 | @objc func onCallNativeCookies() {
89 | // UIWebView 获取Cookies
90 | let cookiesStorage = HTTPCookieStorage.shared
91 | let cookies = cookiesStorage.cookies(for: webView!.url!)
92 |
93 | let selfCookies = cookies!.filter({ (cookie) -> Bool in
94 | return cookie.domain == self.webView!.url!.host
95 | })
96 |
97 | self.showCookies(selfCookies)
98 | }
99 |
100 |
101 | // MARK: - Private
102 | fileprivate func showCookies(_ cookies: [HTTPCookie]) {
103 | let cookiesString = cookies.reduce("", { (re, cookie) -> String in
104 | return re + " \(cookie.name): \(cookie.value)\n"
105 | })
106 | self.lblCookies.text = cookiesString
107 |
108 | DispatchQueue.main.async {
109 | self.lblCookies.isHidden = false
110 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 15, execute: {
111 | self.lblCookies.isHidden = true
112 | })
113 | }
114 | }
115 |
116 | }
117 |
118 |
--------------------------------------------------------------------------------
/GTMWebKitExample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
33 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/GTMWebKitExample/Swift Scan/LBXScanViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LBXScanViewController.swift
3 | // swiftScan
4 | //
5 | // Created by lbxia on 15/12/8.
6 | // Copyright © 2015年 xialibing. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Foundation
11 | import AVFoundation
12 |
13 | public protocol LBXScanViewControllerDelegate {
14 | func scanFinished(scanResult: LBXScanResult, error: String?)
15 | }
16 |
17 |
18 | open class LBXScanViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
19 |
20 | //返回扫码结果,也可以通过继承本控制器,改写该handleCodeResult方法即可
21 | open var scanResultDelegate: LBXScanViewControllerDelegate?
22 |
23 | open var scanObj: LBXScanWrapper?
24 |
25 | open var scanStyle: LBXScanViewStyle? = LBXScanViewStyle()
26 |
27 | open var qRScanView: LBXScanView?
28 |
29 |
30 | //启动区域识别功能
31 | open var isOpenInterestRect = false
32 |
33 | //识别码的类型
34 | public var arrayCodeType:[AVMetadataObject.ObjectType]?
35 |
36 | //是否需要识别后的当前图像
37 | public var isNeedCodeImage = false
38 |
39 | //相机启动提示文字
40 | public var readyString:String! = "loading"
41 |
42 | override open func viewDidLoad() {
43 | super.viewDidLoad()
44 |
45 | // Do any additional setup after loading the view.
46 |
47 | // [self.view addSubview:_qRScanView];
48 | self.view.backgroundColor = UIColor.black
49 | self.edgesForExtendedLayout = UIRectEdge(rawValue: 0)
50 | }
51 |
52 | open func setNeedCodeImage(needCodeImg:Bool)
53 | {
54 | isNeedCodeImage = needCodeImg;
55 | }
56 | //设置框内识别
57 | open func setOpenInterestRect(isOpen:Bool){
58 | isOpenInterestRect = isOpen
59 | }
60 |
61 | override open func viewWillAppear(_ animated: Bool) {
62 | super.viewWillAppear(animated)
63 | }
64 |
65 | override open func viewDidAppear(_ animated: Bool) {
66 |
67 | super.viewDidAppear(animated)
68 |
69 | drawScanView()
70 |
71 | perform(#selector(LBXScanViewController.startScan), with: nil, afterDelay: 0.3)
72 |
73 | }
74 |
75 | @objc open func startScan()
76 | {
77 |
78 | if (scanObj == nil)
79 | {
80 | var cropRect = CGRect.zero
81 | if isOpenInterestRect
82 | {
83 | cropRect = LBXScanView.getScanRectWithPreView(preView: self.view, style:scanStyle! )
84 | }
85 |
86 | //指定识别几种码
87 | if arrayCodeType == nil
88 | {
89 | arrayCodeType = [AVMetadataObject.ObjectType.qr,AVMetadataObject.ObjectType.ean13,AVMetadataObject.ObjectType.code128]
90 | }
91 |
92 | scanObj = LBXScanWrapper(videoPreView: self.view,objType:arrayCodeType!, isCaptureImg: isNeedCodeImage,cropRect:cropRect, success: { [weak self] (arrayResult) -> Void in
93 |
94 | if let strongSelf = self
95 | {
96 | //停止扫描动画
97 | strongSelf.qRScanView?.stopScanAnimation()
98 |
99 | strongSelf.handleCodeResult(arrayResult: arrayResult)
100 | }
101 | })
102 | }
103 |
104 | //结束相机等待提示
105 | qRScanView?.deviceStopReadying()
106 |
107 | //开始扫描动画
108 | qRScanView?.startScanAnimation()
109 |
110 | //相机运行
111 | scanObj?.start()
112 | }
113 |
114 | open func drawScanView()
115 | {
116 | if qRScanView == nil
117 | {
118 | qRScanView = LBXScanView(frame: self.view.frame,vstyle:scanStyle! )
119 | self.view.addSubview(qRScanView!)
120 | }
121 | qRScanView?.deviceStartReadying(readyStr: readyString)
122 |
123 | }
124 |
125 |
126 | /**
127 | 处理扫码结果,如果是继承本控制器的,可以重写该方法,作出相应地处理,或者设置delegate作出相应处理
128 | */
129 | open func handleCodeResult(arrayResult:[LBXScanResult])
130 | {
131 | if let delegate = scanResultDelegate {
132 |
133 | self.navigationController? .popViewController(animated: true)
134 | let result:LBXScanResult = arrayResult[0]
135 |
136 | delegate.scanFinished(scanResult: result, error: nil)
137 |
138 | }else{
139 |
140 | for result:LBXScanResult in arrayResult
141 | {
142 | print("%@",result.strScanned ?? "")
143 | }
144 |
145 | let result:LBXScanResult = arrayResult[0]
146 |
147 | showMsg(title: result.strBarCodeType, message: result.strScanned)
148 | }
149 | }
150 |
151 | override open func viewWillDisappear(_ animated: Bool) {
152 |
153 | NSObject.cancelPreviousPerformRequests(withTarget: self)
154 |
155 | qRScanView?.stopScanAnimation()
156 |
157 | scanObj?.stop()
158 | }
159 |
160 | open func openPhotoAlbum()
161 | {
162 | LBXPermissions.authorizePhotoWith { [weak self] (granted) in
163 |
164 | let picker = UIImagePickerController()
165 |
166 | picker.sourceType = UIImagePickerController.SourceType.photoLibrary
167 |
168 | picker.delegate = self;
169 |
170 | picker.allowsEditing = true
171 |
172 | self?.present(picker, animated: true, completion: nil)
173 | }
174 | }
175 |
176 | //MARK: -----相册选择图片识别二维码 (条形码没有找到系统方法)
177 | public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
178 | {
179 | picker.dismiss(animated: true, completion: nil)
180 |
181 | var image: UIImage? = info[UIImagePickerController.InfoKey.editedImage.rawValue] as? UIImage
182 |
183 | if (image == nil ) {
184 | image = info[UIImagePickerController.InfoKey.originalImage.rawValue] as? UIImage
185 | }
186 |
187 | if(image != nil)
188 | {
189 | let arrayResult = LBXScanWrapper.recognizeQRImage(image: image!)
190 | if arrayResult.count > 0
191 | {
192 | handleCodeResult(arrayResult: arrayResult)
193 | return
194 | }
195 | }
196 |
197 | showMsg(title: nil, message: NSLocalizedString("Identify failed", comment: "Identify failed"))
198 | }
199 |
200 | func showMsg(title:String?,message:String?)
201 | {
202 |
203 | let alertController = UIAlertController(title: nil, message:message, preferredStyle: UIAlertController.Style.alert)
204 | let alertAction = UIAlertAction(title: NSLocalizedString("OK", comment: "OK"), style: UIAlertAction.Style.default) { (alertAction) in
205 |
206 | // if let strongSelf = self
207 | // {
208 | // strongSelf.startScan()
209 | // }
210 | }
211 |
212 | alertController.addAction(alertAction)
213 | present(alertController, animated: true, completion: nil)
214 | }
215 | deinit
216 | {
217 | // print("LBXScanViewController deinit")
218 | }
219 |
220 | }
221 |
222 |
223 |
224 |
225 |
226 |
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebView+WKWebView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GTMWebView+WKWebView.swift
3 | // GTMWebKit
4 | //
5 | // Created by luoyang on 2017/11/9.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 |
12 | // MARK: - WKWebView
13 | extension GTMWebViewController: WKNavigationDelegate {
14 |
15 | public var wkWebView: WKWebView? {
16 | return self.webView
17 | }
18 |
19 | func setupWkWebView() {
20 |
21 | // init weakScriptHandler
22 | self.weakScriptHandler = WeakScriptMessageHandler(self)
23 |
24 | let configuration = WKWebViewConfiguration() // 配置
25 | configuration.processPool = GTMWebViewController.sharedProcessPool // WkWebView 实例间共享Cookies
26 | configuration.preferences.minimumFontSize = 1
27 | configuration.preferences.javaScriptEnabled = true
28 | configuration.allowsInlineMediaPlayback = true // 允许视频播放回退
29 | configuration.userContentController = WKUserContentController() // 交互对象
30 | configuration.userContentController.add(self.weakScriptHandler, name: "GTMWebKitAPI")
31 | let wkWebV = WKWebView(frame: self.view.bounds, configuration: configuration) // WKWebView
32 | wkWebV.uiDelegate = self
33 | wkWebV.navigationDelegate = self
34 | wkWebV.allowsBackForwardNavigationGestures = true
35 | self.view.addSubview(wkWebV)
36 | self.webView = wkWebV
37 | }
38 |
39 | // MARK: - KVO
40 |
41 | public func wkwebv_addObservers() {
42 | wkWebView?.addObserver(self, forKeyPath: "loading", options: .new, context: nil)
43 | wkWebView?.addObserver(self, forKeyPath: "title", options: .new, context: nil)
44 | wkWebView?.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
45 | }
46 |
47 | public func wkwebv_removeObservers() {
48 | wkWebView?.removeObserver(self, forKeyPath: "loading")
49 | wkWebView?.removeObserver(self, forKeyPath: "title")
50 | wkWebView?.removeObserver(self, forKeyPath: "estimatedProgress")
51 | }
52 |
53 | public func wkwebv_observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
54 | if keyPath == "loading" {
55 | println("loading")
56 | } else if keyPath == "title" {
57 | if isUseWebTitle {
58 | self.title = self.webView.title
59 | }
60 | self.updateButtonItems() // 更新导航按钮状态
61 | } else if keyPath == "estimatedProgress" {
62 | self.progressView?.isHidden = false
63 | self.progressView?.setProgress(Float(wkWebView!.estimatedProgress), animated: true)
64 | }
65 |
66 | // 已经完成加载时,我们就可以做我们的事了
67 | if !wkWebView!.isLoading {
68 | self.progressView?.setProgress(0, animated: false)
69 | self.progressView?.isHidden = true
70 | }
71 | }
72 |
73 | // MARK: - WKNavigationDelegate
74 | public func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
75 | self.webWillLoad()
76 | }
77 | // MARK: Initiating the Navigation
78 | public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
79 |
80 | }
81 | // MARK: Responding to Server Actions
82 | public func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
83 |
84 | println(navigation.description)
85 | }
86 | // Authentication Challenges
87 | public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
88 |
89 | var disposition: URLSession.AuthChallengeDisposition = URLSession.AuthChallengeDisposition.performDefaultHandling
90 | var credential: URLCredential?
91 |
92 | if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
93 | disposition = URLSession.AuthChallengeDisposition.useCredential
94 | credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
95 | }
96 |
97 | completionHandler(disposition, credential)
98 | }
99 | // MARK: Tracking Load Progress
100 | public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
101 | println("webView didFinish")
102 | // 共享 Cookies
103 | if isNeedShareCookies {
104 | if #available(iOS 11.0, *) {
105 | GTMWebViewCookies.shareWebViewCookies(url: webView.url!)
106 | }
107 | }
108 | self.webDidLoad()
109 | }
110 | public func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
111 | // 如果出现频繁刷新的情况,说明页面占用内存确实过大,需要前端作优化处理
112 | if self.isTreatMemeryCrushWithReload {
113 | webView.reload() // 解决内存消耗过度出现白屏的问题
114 | }
115 | }
116 | // MARK: Permitting Navigation
117 | public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
118 |
119 | // Disable all the '_blank' target in page's target
120 | if let frame = navigationAction.targetFrame {
121 | if frame.isMainFrame {
122 | webView.evaluateJavaScript("var a = document.getElementsByTagName('a');for(var i=0;i Void) {
164 |
165 | println("decidePolicyFor navigationResponse")
166 | decisionHandler(.allow)
167 | }
168 | // MARK: Reacting to Errors
169 | public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
170 | let nserror = error as NSError
171 | if nserror.code == NSURLErrorCancelled {
172 | return
173 | }
174 | self.webDidLoadFail(error: nserror)
175 | }
176 | public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
177 | let nserror = error as NSError
178 | if nserror.code == NSURLErrorCancelled {
179 | return
180 | }
181 | self.webDidLoadFail(error: nserror)
182 | }
183 | }
184 |
185 | extension GTMWebViewController: WKScriptMessageHandler {
186 |
187 | public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
188 | if message.name == "GTMWebKitAPI" {
189 | if let body = message.body as? Dictionary {
190 | let method = body["method"] as! String
191 | println("\(body)")
192 | println("\(method)")
193 |
194 | if let handler = self.scriptHandlers[method] {
195 | handler(body["body"])
196 | }
197 | }
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/GTMWebKitExample/Swift Scan/LBXScanView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LBXScanView.swift
3 | // swiftScan
4 | //
5 | // Created by xialibing on 15/12/8.
6 | // Copyright © 2015年 xialibing. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | open class LBXScanView: UIView
12 | {
13 | //扫码区域各种参数
14 | var viewStyle:LBXScanViewStyle = LBXScanViewStyle()
15 |
16 | //扫码区域
17 | var scanRetangleRect:CGRect = CGRect.zero
18 |
19 | //线条扫码动画封装
20 | var scanLineAnimation:LBXScanLineAnimation?
21 |
22 | //网格扫码动画封装
23 | var scanNetAnimation:LBXScanNetAnimation?
24 |
25 | //线条在中间位置,不移动
26 | var scanLineStill:UIImageView?
27 |
28 | //启动相机时 菊花等待
29 | var activityView:UIActivityIndicatorView?
30 |
31 | //启动相机中的提示文字
32 | var labelReadying:UILabel?
33 |
34 | //记录动画状态
35 | var isAnimationing:Bool = false
36 |
37 | /**
38 | 初始化扫描界面
39 | - parameter frame: 界面大小,一般为视频显示区域
40 | - parameter vstyle: 界面效果参数
41 |
42 | - returns: instancetype
43 | */
44 | public init(frame:CGRect, vstyle:LBXScanViewStyle )
45 | {
46 | viewStyle = vstyle
47 |
48 | switch (viewStyle.anmiationStyle)
49 | {
50 | case LBXScanViewAnimationStyle.LineMove:
51 | scanLineAnimation = LBXScanLineAnimation.instance()
52 | break
53 | case LBXScanViewAnimationStyle.NetGrid:
54 | scanNetAnimation = LBXScanNetAnimation.instance()
55 | break
56 | case LBXScanViewAnimationStyle.LineStill:
57 | scanLineStill = UIImageView()
58 | scanLineStill?.image = viewStyle.animationImage
59 | break
60 |
61 |
62 | default:
63 | break
64 | }
65 |
66 | var frameTmp = frame;
67 | frameTmp.origin = CGPoint.zero
68 |
69 | super.init(frame: frameTmp)
70 |
71 | backgroundColor = UIColor.clear
72 | }
73 |
74 | override init(frame: CGRect) {
75 |
76 | var frameTmp = frame;
77 | frameTmp.origin = CGPoint.zero
78 |
79 | super.init(frame: frameTmp)
80 |
81 | backgroundColor = UIColor.clear
82 | }
83 |
84 | required public init?(coder aDecoder: NSCoder)
85 | {
86 | self.init()
87 |
88 | }
89 |
90 | deinit
91 | {
92 | if (scanLineAnimation != nil)
93 | {
94 | scanLineAnimation!.stopStepAnimating()
95 | }
96 | if (scanNetAnimation != nil)
97 | {
98 | scanNetAnimation!.stopStepAnimating()
99 | }
100 |
101 |
102 | // print("LBXScanView deinit")
103 | }
104 |
105 |
106 | /**
107 | * 开始扫描动画
108 | */
109 | func startScanAnimation()
110 | {
111 | if isAnimationing
112 | {
113 | return
114 | }
115 |
116 | isAnimationing = true
117 |
118 | let cropRect:CGRect = getScanRectForAnimation()
119 |
120 | switch viewStyle.anmiationStyle
121 | {
122 | case LBXScanViewAnimationStyle.LineMove:
123 |
124 | // print(NSStringFromCGRect(cropRect))
125 |
126 | scanLineAnimation!.startAnimatingWithRect(animationRect: cropRect, parentView: self, image:viewStyle.animationImage )
127 | break
128 | case LBXScanViewAnimationStyle.NetGrid:
129 |
130 | scanNetAnimation!.startAnimatingWithRect(animationRect: cropRect, parentView: self, image:viewStyle.animationImage )
131 | break
132 | case LBXScanViewAnimationStyle.LineStill:
133 |
134 | let stillRect = CGRect(x: cropRect.origin.x+20,
135 | y: cropRect.origin.y + cropRect.size.height/2,
136 | width: cropRect.size.width-40,
137 | height: 2);
138 | self.scanLineStill?.frame = stillRect
139 |
140 | self.addSubview(scanLineStill!)
141 | self.scanLineStill?.isHidden = false
142 |
143 | break
144 |
145 | default: break
146 |
147 | }
148 | }
149 |
150 | /**
151 | * 开始扫描动画
152 | */
153 | func stopScanAnimation()
154 | {
155 | isAnimationing = false
156 |
157 | switch viewStyle.anmiationStyle
158 | {
159 | case LBXScanViewAnimationStyle.LineMove:
160 |
161 | scanLineAnimation?.stopStepAnimating()
162 | break
163 | case LBXScanViewAnimationStyle.NetGrid:
164 |
165 | scanNetAnimation?.stopStepAnimating()
166 | break
167 | case LBXScanViewAnimationStyle.LineStill:
168 | self.scanLineStill?.isHidden = true
169 |
170 | break
171 |
172 | default: break
173 |
174 | }
175 | }
176 |
177 |
178 |
179 | // Only override drawRect: if you perform custom drawing.
180 | // An empty implementation adversely affects performance during animation.
181 | override open func draw(_ rect: CGRect)
182 | {
183 | // Drawing code
184 | drawScanRect()
185 | }
186 |
187 | //MARK:----- 绘制扫码效果-----
188 | func drawScanRect()
189 | {
190 | let XRetangleLeft = viewStyle.xScanRetangleOffset
191 | var sizeRetangle = CGSize(width: self.frame.size.width - XRetangleLeft*2.0, height: self.frame.size.width - XRetangleLeft*2.0)
192 | if viewStyle.whRatio != 1.0
193 | {
194 | let w = sizeRetangle.width;
195 | var h:CGFloat = w / viewStyle.whRatio
196 |
197 | let hInt:Int = Int(h)
198 | h = CGFloat(hInt)
199 |
200 | sizeRetangle = CGSize(width: w, height: h)
201 | }
202 |
203 | //扫码区域Y轴最小坐标
204 | let YMinRetangle = self.frame.size.height / 2.0 - sizeRetangle.height/2.0 - viewStyle.centerUpOffset
205 | let YMaxRetangle = YMinRetangle + sizeRetangle.height
206 | let XRetangleRight = self.frame.size.width - XRetangleLeft
207 |
208 |
209 | // print("frame:%@",NSStringFromCGRect(self.frame))
210 |
211 | let context = UIGraphicsGetCurrentContext()!
212 |
213 |
214 | //非扫码区域半透明
215 | //设置非识别区域颜色
216 | context.setFillColor(viewStyle.color_NotRecoginitonArea.cgColor)
217 | //填充矩形
218 | //扫码区域上面填充
219 | var rect = CGRect(x: 0, y: 0, width: self.frame.size.width, height: YMinRetangle)
220 | context.fill(rect)
221 |
222 |
223 | //扫码区域左边填充
224 | rect = CGRect(x: 0, y: YMinRetangle, width: XRetangleLeft, height: sizeRetangle.height)
225 | context.fill(rect)
226 |
227 | //扫码区域右边填充
228 | rect = CGRect(x: XRetangleRight, y: YMinRetangle, width: XRetangleLeft,height: sizeRetangle.height)
229 | context.fill(rect)
230 |
231 | //扫码区域下面填充
232 | rect = CGRect(x: 0, y: YMaxRetangle, width: self.frame.size.width,height: self.frame.size.height - YMaxRetangle)
233 | context.fill(rect)
234 | //执行绘画
235 | context.strokePath()
236 |
237 |
238 | if viewStyle.isNeedShowRetangle
239 | {
240 | //中间画矩形(正方形)
241 | context.setStrokeColor(viewStyle.colorRetangleLine.cgColor)
242 | context.setLineWidth(1);
243 |
244 | context.addRect(CGRect(x: XRetangleLeft, y: YMinRetangle, width: sizeRetangle.width, height: sizeRetangle.height))
245 |
246 | //CGContextMoveToPoint(context, XRetangleLeft, YMinRetangle);
247 | //CGContextAddLineToPoint(context, XRetangleLeft+sizeRetangle.width, YMinRetangle);
248 |
249 | context.strokePath()
250 |
251 | }
252 | scanRetangleRect = CGRect(x: XRetangleLeft, y: YMinRetangle, width: sizeRetangle.width, height: sizeRetangle.height)
253 |
254 |
255 | //画矩形框4格外围相框角
256 |
257 | //相框角的宽度和高度
258 | let wAngle = viewStyle.photoframeAngleW;
259 | let hAngle = viewStyle.photoframeAngleH;
260 |
261 | //4个角的 线的宽度
262 | let linewidthAngle = viewStyle.photoframeLineW;// 经验参数:6和4
263 |
264 | //画扫码矩形以及周边半透明黑色坐标参数
265 | var diffAngle = linewidthAngle/3;
266 | diffAngle = linewidthAngle / 2; //框外面4个角,与框有缝隙
267 | diffAngle = linewidthAngle/2; //框4个角 在线上加4个角效果
268 | diffAngle = 0;//与矩形框重合
269 |
270 | switch viewStyle.photoframeAngleStyle
271 | {
272 | case LBXScanViewPhotoframeAngleStyle.Outer:
273 | diffAngle = linewidthAngle/3//框外面4个角,与框紧密联系在一起
274 |
275 | case LBXScanViewPhotoframeAngleStyle.On:
276 | diffAngle = 0
277 |
278 | case LBXScanViewPhotoframeAngleStyle.Inner:
279 | diffAngle = -viewStyle.photoframeLineW/2
280 | }
281 |
282 | context.setStrokeColor(viewStyle.colorAngle.cgColor);
283 | context.setFillColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0);
284 |
285 | // Draw them with a 2.0 stroke width so they are a bit more visible.
286 | context.setLineWidth(linewidthAngle);
287 |
288 |
289 | //
290 | let leftX = XRetangleLeft - diffAngle
291 | let topY = YMinRetangle - diffAngle
292 | let rightX = XRetangleRight + diffAngle
293 | let bottomY = YMaxRetangle + diffAngle
294 |
295 | //左上角水平线
296 | context.move(to: CGPoint(x: leftX-linewidthAngle/2, y: topY))
297 | context.addLine(to: CGPoint(x: leftX + wAngle, y: topY))
298 |
299 | //左上角垂直线
300 | context.move(to: CGPoint(x: leftX, y: topY-linewidthAngle/2))
301 | context.addLine(to: CGPoint(x: leftX, y: topY+hAngle))
302 |
303 | //左下角水平线
304 | context.move(to: CGPoint(x: leftX-linewidthAngle/2, y: bottomY))
305 | context.addLine(to: CGPoint(x: leftX + wAngle, y: bottomY))
306 |
307 | //左下角垂直线
308 | context.move(to: CGPoint(x: leftX, y: bottomY+linewidthAngle/2))
309 | context.addLine(to: CGPoint(x: leftX, y: bottomY - hAngle))
310 |
311 | //右上角水平线
312 | context.move(to: CGPoint(x: rightX+linewidthAngle/2, y: topY))
313 | context.addLine(to: CGPoint(x: rightX - wAngle, y: topY))
314 |
315 | //右上角垂直线
316 | context.move(to: CGPoint(x: rightX, y: topY-linewidthAngle/2))
317 | context.addLine(to: CGPoint(x: rightX, y: topY + hAngle))
318 |
319 | // 右下角水平线
320 | context.move(to: CGPoint(x: rightX+linewidthAngle/2, y: bottomY))
321 | context.addLine(to: CGPoint(x: rightX - wAngle, y: bottomY))
322 |
323 | //右下角垂直线
324 | context.move(to: CGPoint(x: rightX, y: bottomY+linewidthAngle/2))
325 | context.addLine(to: CGPoint(x: rightX, y: bottomY - hAngle))
326 |
327 | context.strokePath()
328 | }
329 |
330 | func getScanRectForAnimation() -> CGRect
331 | {
332 | let XRetangleLeft = viewStyle.xScanRetangleOffset
333 | var sizeRetangle = CGSize(width: self.frame.size.width - XRetangleLeft*2, height: self.frame.size.width - XRetangleLeft*2)
334 |
335 | if viewStyle.whRatio != 1
336 | {
337 | let w = sizeRetangle.width
338 | var h = w / viewStyle.whRatio
339 |
340 |
341 | let hInt:Int = Int(h)
342 | h = CGFloat(hInt)
343 |
344 | sizeRetangle = CGSize(width: w, height: h)
345 | }
346 |
347 | //扫码区域Y轴最小坐标
348 | let YMinRetangle = self.frame.size.height / 2.0 - sizeRetangle.height/2.0 - viewStyle.centerUpOffset
349 | //扫码区域坐标
350 | let cropRect = CGRect(x: XRetangleLeft, y: YMinRetangle, width: sizeRetangle.width, height: sizeRetangle.height)
351 |
352 | return cropRect;
353 | }
354 |
355 | //根据矩形区域,获取识别区域
356 | static func getScanRectWithPreView(preView:UIView, style:LBXScanViewStyle) -> CGRect
357 | {
358 | let XRetangleLeft = style.xScanRetangleOffset;
359 | var sizeRetangle = CGSize(width: preView.frame.size.width - XRetangleLeft*2, height: preView.frame.size.width - XRetangleLeft*2)
360 |
361 | if style.whRatio != 1
362 | {
363 | let w = sizeRetangle.width
364 | var h = w / style.whRatio
365 |
366 | let hInt:Int = Int(h)
367 | h = CGFloat(hInt)
368 |
369 | sizeRetangle = CGSize(width: w, height: h)
370 | }
371 |
372 | //扫码区域Y轴最小坐标
373 | let YMinRetangle = preView.frame.size.height / 2.0 - sizeRetangle.height/2.0 - style.centerUpOffset
374 | //扫码区域坐标
375 | let cropRect = CGRect(x: XRetangleLeft, y: YMinRetangle, width: sizeRetangle.width, height: sizeRetangle.height)
376 |
377 |
378 | //计算兴趣区域
379 | var rectOfInterest:CGRect
380 |
381 | //ref:http://www.cocoachina.com/ios/20141225/10763.html
382 | let size = preView.bounds.size;
383 | let p1 = size.height/size.width;
384 |
385 | let p2:CGFloat = 1920.0/1080.0 //使用了1080p的图像输出
386 | if p1 < p2 {
387 | let fixHeight = size.width * 1920.0 / 1080.0;
388 | let fixPadding = (fixHeight - size.height)/2;
389 | rectOfInterest = CGRect(x: (cropRect.origin.y + fixPadding)/fixHeight,
390 | y: cropRect.origin.x/size.width,
391 | width: cropRect.size.height/fixHeight,
392 | height: cropRect.size.width/size.width)
393 |
394 |
395 | } else {
396 | let fixWidth = size.height * 1080.0 / 1920.0;
397 | let fixPadding = (fixWidth - size.width)/2;
398 | rectOfInterest = CGRect(x: cropRect.origin.y/size.height,
399 | y: (cropRect.origin.x + fixPadding)/fixWidth,
400 | width: cropRect.size.height/size.height,
401 | height: cropRect.size.width/fixWidth)
402 | }
403 | return rectOfInterest
404 | }
405 |
406 | func getRetangeSize()->CGSize
407 | {
408 | let XRetangleLeft = viewStyle.xScanRetangleOffset
409 |
410 | var sizeRetangle = CGSize(width: self.frame.size.width - XRetangleLeft*2, height: self.frame.size.width - XRetangleLeft*2)
411 |
412 | let w = sizeRetangle.width;
413 | var h = w / viewStyle.whRatio;
414 |
415 |
416 | let hInt:Int = Int(h)
417 | h = CGFloat(hInt)
418 |
419 | sizeRetangle = CGSize(width: w, height: h)
420 |
421 | return sizeRetangle
422 | }
423 |
424 | func deviceStartReadying(readyStr:String)
425 | {
426 | let XRetangleLeft = viewStyle.xScanRetangleOffset
427 |
428 | let sizeRetangle = getRetangeSize()
429 |
430 | //扫码区域Y轴最小坐标
431 | let YMinRetangle = self.frame.size.height / 2.0 - sizeRetangle.height/2.0 - viewStyle.centerUpOffset
432 |
433 | //设备启动状态提示
434 | if (activityView == nil)
435 | {
436 | self.activityView = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
437 |
438 | activityView?.center = CGPoint(x: XRetangleLeft + sizeRetangle.width/2 - 50, y: YMinRetangle + sizeRetangle.height/2)
439 | activityView?.style = UIActivityIndicatorView.Style.whiteLarge
440 |
441 | addSubview(activityView!)
442 |
443 |
444 | let labelReadyRect = CGRect(x: activityView!.frame.origin.x + activityView!.frame.size.width + 10, y: activityView!.frame.origin.y, width: 100, height: 30);
445 | //print("%@",NSStringFromCGRect(labelReadyRect))
446 | self.labelReadying = UILabel(frame: labelReadyRect)
447 | labelReadying?.text = readyStr
448 | labelReadying?.backgroundColor = UIColor.clear
449 | labelReadying?.textColor = UIColor.white
450 | labelReadying?.font = UIFont.systemFont(ofSize: 18.0)
451 | addSubview(labelReadying!)
452 | }
453 |
454 | addSubview(labelReadying!)
455 | activityView?.startAnimating()
456 |
457 | }
458 |
459 | func deviceStopReadying()
460 | {
461 | if activityView != nil
462 | {
463 | activityView?.stopAnimating()
464 | activityView?.removeFromSuperview()
465 | labelReadying?.removeFromSuperview()
466 |
467 | activityView = nil
468 | labelReadying = nil
469 |
470 | }
471 | }
472 |
473 | }
474 |
--------------------------------------------------------------------------------
/GTMWebKit/GTMWebViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GTMWebViewController.swift
3 | // GTMWebKit
4 | //
5 | // Created by luoyang on 2017/10/25.
6 | // Copyright © 2017年 yang. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 |
12 | public enum GTMWK_NavigationType {
13 | case navbar // web导航控制按钮放在导航栏
14 | case toolbar // web导航控制按钮放在底部工具栏
15 | case both // 同时使用两种导航按钮
16 | case none // 不使用web导航按钮
17 | }
18 |
19 | open class GTMWebViewController: UIViewController, GTMAlertable {
20 |
21 | // MARK: - 通用属性
22 | public var webView: WKWebView!
23 | public var isShowCloseItem = true // 是否显示关闭按钮(navigType == .navbar 时使用)
24 | public var isShowToolbar = true // 是否显示工具栏(navigType == .toolbar 时使用)
25 | public var isNeedShareCookies = false // 是否需要共享cookies
26 | public var isUseWebTitle = true // 是否使用网页的title
27 | public var backIconName: String? // 返回按钮图标,可自行设置
28 | public var view404: GTMWebErrorView! // 资源不存在的时候展示的UI,可自定义
29 | public var netErrorView: GTMWebErrorView! // 网络错误的时候展示的UI,可自定义
30 |
31 |
32 | // Private props
33 | private var webUrl: URL?
34 | /// 网页加载进度指示器
35 | var progressView: UIProgressView?
36 |
37 | private var navigType: GTMWK_NavigationType // 控制网页导航的方式(导航栏,工具栏)
38 | // MARK: Navigation Items
39 | var navbarItemBack: UIBarButtonItem?
40 | var navbarItemClose: UIBarButtonItem?
41 | // MARK: ToolBar Items
42 | var toolbarItemBack: UIBarButtonItem?
43 | var toolbarItemForward: UIBarButtonItem?
44 | var toolbarItemRefresh: UIBarButtonItem?
45 | var toolbarItemAction: UIBarButtonItem?
46 |
47 |
48 | // MARK: - WKWebView 属性
49 | // 是否使用reload的方式处理内存占用过大造成的白屏问题
50 | // 当打开的时候如果某个页面出现频繁刷新的情况,建议优化网页
51 | public var isTreatMemeryCrushWithReload = false
52 | /// 弱代理(处理内存泄漏的问题)
53 | public var weakScriptHandler: WeakScriptMessageHandler!
54 | /// 提供给JS的API容器
55 | var scriptHandlers: [String: (_ body: Any?) -> Void] = [:]
56 | // Cookies处理属性
57 | public static let sharedProcessPool = WKProcessPool()
58 |
59 |
60 | // MARK: - Life Cycle
61 |
62 | var urlCovertible: URLConvertible?
63 | public init(with url: URLConvertible, navigType type: GTMWK_NavigationType) {
64 | self.navigType = type
65 | super.init(nibName: nil, bundle: nil)
66 | self.urlCovertible = url
67 | self.webUrl = url.url()
68 | self.view404 = GTMWebNetErrorView("404")
69 | self.netErrorView = GTMWebNetErrorView("nosingle")
70 | }
71 |
72 | /// 如果当前不在根页面,回到并重新加载根页面。否则什么都不做
73 | public func reloadToRootPage() -> Bool {
74 | guard let url = self.urlCovertible?.url() else {
75 | return false
76 | }
77 | if self.webView.url!.absoluteString == url.absoluteString {
78 | return false
79 | }
80 | self.loadWithUrl(url: url)
81 | return true
82 | }
83 | /// reload当前页面
84 | public func reload() {
85 | self.webView.reload()
86 | }
87 |
88 | public required init?(coder aDecoder: NSCoder) {
89 | fatalError("init(coder:) has not been implemented")
90 | }
91 |
92 | var originToolBarState: Bool?
93 | var originNavBarState: Bool?
94 | override open func viewDidLoad() {
95 | super.viewDidLoad()
96 |
97 | self.setup()
98 | self.loadWebPage() // 加载网页
99 |
100 | originToolBarState = self.navigationController?.isToolbarHidden
101 | originNavBarState = self.navigationController?.isNavigationBarHidden
102 | }
103 |
104 | override open func viewWillAppear(_ animated: Bool) {
105 | super.viewWillAppear(animated)
106 |
107 | switch navigType {
108 | case .navbar:
109 | self.navigationController?.setToolbarHidden(true, animated: animated)
110 | case .toolbar:
111 | self.navigationController?.setNavigationBarHidden(false, animated: animated)
112 | self.navigationController?.setToolbarHidden(false, animated: animated)
113 | case .both:
114 | self.navigationController?.setToolbarHidden(false, animated: animated)
115 | self.navigationController?.setNavigationBarHidden(false, animated: animated)
116 | case .none:
117 | self.navigationController?.setToolbarHidden(true, animated: animated)
118 | self.navigationController?.setNavigationBarHidden(true, animated: animated)
119 | }
120 | //
121 | self.updateButtonItems() // 更新导航按钮状态
122 | }
123 |
124 | override open func viewWillDisappear(_ animated: Bool) {
125 | super.viewWillDisappear(animated)
126 | guard originNavBarState != nil else {
127 | return
128 | }
129 | self.navigationController?.setToolbarHidden(originToolBarState!, animated: animated)
130 | self.navigationController?.setNavigationBarHidden(originNavBarState!, animated: animated)
131 | }
132 |
133 | private func setup() {
134 | // 导航栏不透明
135 | self.navigationController?.navigationBar.isTranslucent = false
136 |
137 | /// init sub views
138 |
139 | // web view
140 | self.setupWkWebView()
141 |
142 | self.addObservers() // KVO
143 |
144 | // progress view
145 | self.progressView = UIProgressView(progressViewStyle: .default)
146 | self.progressView?.frame = self.view.bounds
147 | self.progressView?.trackTintColor = UIColor.white
148 | self.progressView?.tintColor = UIColor.gray
149 | self.view.addSubview(self.progressView!)
150 |
151 | // init button items
152 | self.initButtonItems()
153 |
154 | // 共享 Cookies
155 | if isNeedShareCookies {
156 | if #available(iOS 11.0, *) {
157 | GTMWebViewCookies.shareNativeCookies(url: self.webUrl!)
158 | }
159 | }
160 |
161 | }
162 |
163 | deinit {
164 | self.removeObservers()
165 | println("GTMWebViewController deinit")
166 | }
167 |
168 | // MARK: - Public
169 | /// 注册API
170 | public func registApi(method methodName: String, with handler: @escaping (_ body: Any?) -> Void) {
171 | // 添加到容器
172 | self.scriptHandlers[methodName] = handler
173 | }
174 | /// 注入JS
175 | public func injectUserScript(script: WKUserScript) {
176 | self.webView.configuration.userContentController.addUserScript(script)
177 | }
178 |
179 | // MARK: - Private
180 | func loadWebPage() {
181 | guard let url = self.webUrl else {
182 | println("没有为GTMWebViewController提供有效的网页URL")
183 | return
184 | }
185 |
186 | self.loadWithUrl(url: url)
187 | }
188 |
189 | func loadWithUrl(url: URL) {
190 | webView.load(URLRequest(url: url))
191 | }
192 |
193 | // MARK: - 钩子函数
194 | // web加载完成(相当于抽象函数)
195 | open func webWillLoad() { }
196 | open func webDidLoad() {
197 | self.view404.removeFromSuperview()
198 | self.netErrorView.removeFromSuperview()
199 | }
200 | // 错误处理
201 | open func webDidLoadFail(error: NSError) {
202 | self.view404.removeFromSuperview()
203 | self.netErrorView.removeFromSuperview()
204 |
205 | if error.code == NSURLErrorCannotFindHost ||
206 | error.code == NSURLErrorCannotConnectToHost ||
207 | error.code == NSURLErrorResourceUnavailable {
208 | view404.reloadHandler = { [weak self] in
209 | self?.loadWebPage()
210 | }
211 | self.view.addSubview(view404)
212 | } else {
213 | netErrorView.reloadHandler = { [weak self] in
214 | self?.loadWebPage()
215 | }
216 | self.view.addSubview(netErrorView)
217 | }
218 | }
219 |
220 | // MARK: - KVO
221 | func addObservers() {
222 | self.wkwebv_addObservers()
223 | }
224 | func removeObservers() {
225 | self.wkwebv_removeObservers()
226 | }
227 | open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
228 | self.wkwebv_observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
229 | }
230 |
231 | }
232 |
233 | extension GTMWebViewController {
234 | // MARK: - Web Navigation Items
235 |
236 | fileprivate func initButtonItems() {
237 |
238 | switch navigType {
239 | case .navbar:
240 | self.initNavigationBarItems()
241 | case .toolbar:
242 | self.initBottomBarItems()
243 | case .both:
244 | self.initNavigationBarItems()
245 | self.initBottomBarItems()
246 | case .none:
247 | break
248 | }
249 | // done
250 | if let navigationC = self.navigationController {
251 | if navigationC.isBeingPresented {
252 | // done item
253 | let title = NSLocalizedString("done", bundle: self.sourceBundle, comment: "")
254 | let doneButton = UIButton.init(type: .custom)
255 | doneButton.frame = CGRect(x: 0, y: 0, width: 40, height: 44)
256 | doneButton.setTitle(title, for: .normal)
257 | doneButton.titleLabel?.font = UIFont.systemFont(ofSize: 15)
258 | doneButton.setTitleColor(self.navigationController?.navigationBar.tintColor, for: .normal)
259 | doneButton.addTarget(self, action: #selector(onNavigationDone), for: .touchUpInside)
260 | let doneButtonItem = UIBarButtonItem.init(customView: doneButton)
261 | self.navigationItem.rightBarButtonItem = doneButtonItem
262 | }
263 | }
264 | // 更新状态
265 | self.updateButtonItems()
266 | }
267 |
268 | // MARK: - Navigation Events
269 |
270 | @objc func onNavigationDone() {
271 | self.dismiss(animated: true, completion: nil)
272 | }
273 |
274 | @objc func onNavigationBack() {
275 | if webView.canGoBack {
276 | self.onWebpageBack()
277 | } else {
278 | self.navigationController?.popViewController(animated: true)
279 | }
280 | }
281 | @objc func onNavigationClose() {
282 | self.navigationController?.popViewController(animated: true)
283 | }
284 |
285 |
286 | @objc func onToolbarBack() {
287 | self.onWebpageBack()
288 | }
289 | @objc func onToolbarForward() {
290 | webView.goForward()
291 | }
292 | @objc func onToolbarRefresh() {
293 | webView.reload()
294 | }
295 | @objc func onToolbarAction() {
296 | if let url = webView.url {
297 | let activityVC = UIActivityViewController.init(activityItems: [url], applicationActivities: nil)
298 | self.present(activityVC, animated: true, completion: nil)
299 | }
300 | }
301 |
302 | func onWebpageBack() {
303 | webView.goBack()
304 | self.updateButtonItems()
305 | }
306 |
307 | // MARK: Navigation Items
308 |
309 | private func initNavigationBarItems() {
310 | let bundle = sourceBundle
311 | var iconBack = UIImage.init(named: "nav_back", in: bundle, compatibleWith: nil)
312 | if let image = self.navigationController?.navigationBar.backIndicatorImage {
313 | iconBack = image
314 | }
315 | let buttonBack = UIButton.init(type: .custom)
316 | buttonBack.setImage(iconBack, for: .normal)
317 | buttonBack.sizeToFit()
318 | // buttonBack.frame = CGRect(x: 0, y: 0, width: 20, height: 44)
319 | // if #available(iOS 11.0, *) {
320 | // buttonBack.imageEdgeInsets = UIEdgeInsets(top: 12, left: 4, bottom: 12, right: 4)
321 | // } else {
322 | // buttonBack.imageEdgeInsets = UIEdgeInsets(top: 12, left: -8, bottom: 12, right: 8)
323 | // }
324 |
325 | if let backIcon = backIconName {
326 | iconBack = UIImage(named: backIcon)
327 | buttonBack.setImage(iconBack, for: .normal)
328 | }
329 | // back item
330 | buttonBack.addTarget(self, action: #selector(onNavigationBack), for: .touchUpInside)
331 | self.navbarItemBack = UIBarButtonItem.init(customView: buttonBack)
332 | // self.navigationItem.setLeftBarButtonItems([self.navbarItemBack!], animated: false)
333 |
334 | // close item
335 | let title = NSLocalizedString("close", bundle: bundle, comment: "")
336 | let closeButton = UIButton.init(type: .custom)
337 | closeButton.setTitle(title, for: .normal)
338 | closeButton.titleLabel?.font = UIFont.systemFont(ofSize: 15)
339 | closeButton.setTitleColor(self.navigationController?.navigationBar.tintColor, for: .normal)
340 | closeButton.frame = CGRect(x: 0, y: 0, width: 40, height: 44)
341 | if #available(iOS 11.0, *) {
342 | closeButton.titleEdgeInsets = UIEdgeInsets(top: 0, left: -10, bottom: 0, right: 10)
343 | } else {
344 | closeButton.titleEdgeInsets = UIEdgeInsets(top: 0, left: -5, bottom: 0, right: 5)
345 | }
346 |
347 | closeButton.addTarget(self, action: #selector(onNavigationClose), for: .touchUpInside)
348 | self.navbarItemClose = UIBarButtonItem.init(customView: closeButton)
349 | }
350 | private func initBottomBarItems() {
351 | let bundle = sourceBundle
352 | var iconBack = UIImage.init(named: "back", in: bundle, compatibleWith: nil)
353 | if let image = self.navigationController?.navigationBar.backIndicatorImage {
354 | iconBack = image
355 | }
356 | let buttonBack = UIButton.init(type: .system)
357 | buttonBack.setImage(iconBack, for: .normal)
358 | buttonBack.sizeToFit()
359 | buttonBack.frame = CGRect(x: 0, y: 0, width: 20, height: 44)
360 | if #available(iOS 11.0, *) {
361 | buttonBack.imageEdgeInsets = UIEdgeInsets(top: 12, left: 4, bottom: 12, right: 4)
362 | } else {
363 | buttonBack.imageEdgeInsets = UIEdgeInsets(top: 12, left: -8, bottom: 12, right: 8)
364 | }
365 | // back item
366 | buttonBack.addTarget(self, action: #selector(onToolbarBack), for: .touchUpInside)
367 | self.toolbarItemBack = UIBarButtonItem.init(customView: buttonBack)
368 | // forward item
369 | let iconForward = UIImage.init(named: "forward", in: bundle, compatibleWith: nil)
370 | let buttonForward = UIButton.init(type: .custom)
371 | buttonForward.setImage(iconForward, for: .normal)
372 | buttonForward.frame = CGRect(x: 0, y: 0, width: 20, height: 44)
373 | if #available(iOS 11.0, *) {
374 | buttonForward.imageEdgeInsets = UIEdgeInsets(top: 12, left: 4, bottom: 12, right: 4)
375 | } else {
376 | buttonForward.imageEdgeInsets = UIEdgeInsets(top: 12, left: 0, bottom: 12, right: 0)
377 | }
378 | buttonForward.addTarget(self, action: #selector(onToolbarForward), for: .touchUpInside)
379 | self.toolbarItemForward = UIBarButtonItem.init(customView: buttonForward)
380 | // refresh item
381 | self.toolbarItemRefresh = UIBarButtonItem.init(barButtonSystemItem: .refresh, target: self, action: #selector(onToolbarRefresh))
382 | // action item
383 | self.toolbarItemAction = UIBarButtonItem.init(barButtonSystemItem: .action, target: self, action: #selector(onToolbarAction))
384 | }
385 |
386 | func updateButtonItems() {
387 | switch navigType {
388 | case .navbar:
389 | self.updateNavbarButtonItems()
390 | case .toolbar:
391 | self.updateToolbarButtonItems()
392 | case .both:
393 | self.updateNavbarButtonItems()
394 | self.updateToolbarButtonItems()
395 | default:
396 | break
397 | }
398 | }
399 | private func updateNavbarButtonItems() {
400 | self.navigationItem.setLeftBarButtonItems(nil, animated: false)
401 | if webView.canGoBack {
402 | self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
403 | if let navigC = self.navigationController {
404 | var items: [UIBarButtonItem] = self.navigationItem.leftBarButtonItems ?? []
405 | if navigC.viewControllers.count > 1 {
406 | if self.isShowCloseItem {
407 | items.insert(self.navbarItemBack!, at: 0)
408 | items.append(self.navbarItemClose!)
409 | self.navigationItem.setLeftBarButtonItems(items, animated: false)
410 | } else {
411 | for (i, item) in items.enumerated() {
412 | if item == self.navbarItemClose! {
413 | items.remove(at: i)
414 | }
415 | }
416 | self.navigationItem.setLeftBarButtonItems(items, animated: false)
417 | }
418 | } else {
419 | if self.isShowCloseItem {
420 | items.insert(self.navbarItemBack!, at: 0)
421 | items.append(self.navbarItemClose!)
422 | self.navigationItem.setLeftBarButtonItems(items, animated: false)
423 | } else {
424 | for (i, item) in items.enumerated() {
425 | if item == self.navbarItemClose! {
426 | items.remove(at: i)
427 | }
428 | }
429 | self.navigationItem.setLeftBarButtonItems(items, animated: false)
430 | }
431 | }
432 | }
433 | } else {
434 | var items: [UIBarButtonItem] = self.navigationItem.leftBarButtonItems ?? []
435 | items.insert(self.navbarItemBack!, at: 0)
436 | self.navigationItem.setLeftBarButtonItems(items, animated: false)
437 | // self.navigationItem.setLeftBarButtonItems(nil, animated: false)
438 | self.navigationController?.interactivePopGestureRecognizer?.delegate = nil
439 | self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
440 | }
441 | }
442 | private func updateToolbarButtonItems() {
443 | self.toolbarItemBack?.isEnabled = webView.canGoBack
444 | self.toolbarItemForward?.isEnabled = webView.canGoForward
445 | self.toolbarItemAction?.isEnabled = !webView.isLoading
446 |
447 | let space = UIBarButtonItem.init(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
448 | let items = [self.toolbarItemBack!, space, self.toolbarItemForward!, space, self.toolbarItemRefresh!, space, self.toolbarItemAction!]
449 | self.navigationController?.toolbar.barStyle = (self.navigationController?.navigationBar.barStyle)!
450 | self.navigationController?.toolbar.tintColor = self.navigationController?.navigationBar.tintColor
451 | self.navigationController?.toolbar.barTintColor = self.navigationController?.navigationBar.barTintColor
452 | self.toolbarItems = items
453 | }
454 | }
455 |
456 |
--------------------------------------------------------------------------------
/GTMWebKitExample/Swift Scan/LBXScanWrapper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LBXScanWrapper.swift
3 | // swiftScan
4 | //
5 | // Created by lbxia on 15/12/10.
6 | // Copyright © 2015年 xialibing. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import AVFoundation
11 |
12 | public struct LBXScanResult {
13 |
14 | //码内容
15 | public var strScanned:String? = ""
16 | //扫描图像
17 | public var imgScanned:UIImage?
18 | //码的类型
19 | public var strBarCodeType:String? = ""
20 |
21 | //码在图像中的位置
22 | public var arrayCorner:[AnyObject]?
23 |
24 | public init(str:String?,img:UIImage?,barCodeType:String?,corner:[AnyObject]?)
25 | {
26 | self.strScanned = str
27 | self.imgScanned = img
28 | self.strBarCodeType = barCodeType
29 | self.arrayCorner = corner
30 | }
31 | }
32 |
33 |
34 |
35 | open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
36 |
37 | let device = AVCaptureDevice.default(for: AVMediaType.video)
38 |
39 | var input:AVCaptureDeviceInput?
40 | var output:AVCaptureMetadataOutput
41 |
42 | let session = AVCaptureSession()
43 | var previewLayer:AVCaptureVideoPreviewLayer?
44 | var stillImageOutput:AVCaptureStillImageOutput?
45 |
46 | //存储返回结果
47 | var arrayResult:[LBXScanResult] = [];
48 |
49 | //扫码结果返回block
50 | var successBlock:([LBXScanResult]) -> Void
51 |
52 | //是否需要拍照
53 | var isNeedCaptureImage:Bool
54 |
55 | //当前扫码结果是否处理
56 | var isNeedScanResult:Bool = true
57 |
58 | /**
59 | 初始化设备
60 | - parameter videoPreView: 视频显示UIView
61 | - parameter objType: 识别码的类型,缺省值 QR二维码
62 | - parameter isCaptureImg: 识别后是否采集当前照片
63 | - parameter cropRect: 识别区域
64 | - parameter success: 返回识别信息
65 | - returns:
66 | */
67 | init( videoPreView:UIView,objType:[AVMetadataObject.ObjectType] = [AVMetadataObject.ObjectType.qr],isCaptureImg:Bool,cropRect:CGRect=CGRect.zero,success:@escaping ( ([LBXScanResult]) -> Void) )
68 | {
69 | do{
70 | input = try AVCaptureDeviceInput(device: device!)
71 | }
72 | catch let error as NSError {
73 | print("AVCaptureDeviceInput(): \(error)")
74 | }
75 |
76 | successBlock = success
77 |
78 | // Output
79 | output = AVCaptureMetadataOutput()
80 |
81 | isNeedCaptureImage = isCaptureImg
82 |
83 | stillImageOutput = AVCaptureStillImageOutput();
84 |
85 | super.init()
86 |
87 | if device == nil
88 | {
89 | return
90 | }
91 |
92 | if session.canAddInput(input!)
93 | {
94 | session.addInput(input!)
95 | }
96 | if session.canAddOutput(output)
97 | {
98 | session.addOutput(output)
99 | }
100 | if session.canAddOutput(stillImageOutput!)
101 | {
102 | session.addOutput(stillImageOutput!)
103 | }
104 |
105 | let outputSettings:Dictionary = [AVVideoCodecJPEG:AVVideoCodecKey]
106 | stillImageOutput?.outputSettings = outputSettings
107 |
108 | session.sessionPreset = AVCaptureSession.Preset.high
109 |
110 | //参数设置
111 | output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
112 |
113 | output.metadataObjectTypes = objType
114 |
115 | // output.metadataObjectTypes = [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]
116 |
117 | if !cropRect.equalTo(CGRect.zero)
118 | {
119 | //启动相机后,直接修改该参数无效
120 | output.rectOfInterest = cropRect
121 | }
122 |
123 | previewLayer = AVCaptureVideoPreviewLayer(session: session)
124 | previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
125 |
126 | var frame:CGRect = videoPreView.frame
127 | frame.origin = CGPoint.zero
128 | previewLayer?.frame = frame
129 |
130 | videoPreView.layer .insertSublayer(previewLayer!, at: 0)
131 |
132 | if ( device!.isFocusPointOfInterestSupported && device!.isFocusModeSupported(AVCaptureDevice.FocusMode.continuousAutoFocus) )
133 | {
134 | do
135 | {
136 | try input?.device.lockForConfiguration()
137 |
138 | input?.device.focusMode = AVCaptureDevice.FocusMode.continuousAutoFocus
139 |
140 | input?.device.unlockForConfiguration()
141 | }
142 | catch let error as NSError {
143 | print("device.lockForConfiguration(): \(error)")
144 |
145 | }
146 | }
147 |
148 | }
149 |
150 | public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
151 | captureOutput(output, didOutputMetadataObjects: metadataObjects, from: connection)
152 | }
153 |
154 | func start()
155 | {
156 | if !session.isRunning
157 | {
158 | isNeedScanResult = true
159 | session.startRunning()
160 | }
161 | }
162 | func stop()
163 | {
164 | if session.isRunning
165 | {
166 | isNeedScanResult = false
167 | session.stopRunning()
168 | }
169 | }
170 |
171 | open func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
172 |
173 | if !isNeedScanResult
174 | {
175 | //上一帧处理中
176 | return
177 | }
178 |
179 | isNeedScanResult = false
180 |
181 | arrayResult.removeAll()
182 |
183 | //识别扫码类型
184 | for current:Any in metadataObjects
185 | {
186 | if (current as AnyObject).isKind(of: AVMetadataMachineReadableCodeObject.self)
187 | {
188 | let code = current as! AVMetadataMachineReadableCodeObject
189 |
190 | //码类型
191 | let codeType = code.type
192 | // print("code type:%@",codeType)
193 | //码内容
194 | let codeContent = code.stringValue
195 | // print("code string:%@",codeContent)
196 |
197 | //4个字典,分别 左上角-右上角-右下角-左下角的 坐标百分百,可以使用这个比例抠出码的图像
198 | // let arrayRatio = code.corners
199 |
200 | arrayResult.append(LBXScanResult(str: codeContent, img: UIImage(), barCodeType: codeType.rawValue, corner: code.corners as [AnyObject]?))
201 | }
202 | }
203 |
204 | if arrayResult.count > 0
205 | {
206 | if isNeedCaptureImage
207 | {
208 | captureImage()
209 | }
210 | else
211 | {
212 | stop()
213 | successBlock(arrayResult)
214 | }
215 |
216 | }
217 | else
218 | {
219 | isNeedScanResult = true
220 | }
221 |
222 | }
223 |
224 | //MARK: ----拍照
225 | open func captureImage()
226 | {
227 | let stillImageConnection:AVCaptureConnection? = connectionWithMediaType(mediaType: AVMediaType.video, connections: (stillImageOutput?.connections)! as [AnyObject])
228 |
229 |
230 | stillImageOutput?.captureStillImageAsynchronously(from: stillImageConnection!, completionHandler: { (imageDataSampleBuffer, error) -> Void in
231 |
232 | self.stop()
233 | if imageDataSampleBuffer != nil
234 | {
235 | let imageData: Data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer!)!
236 | let scanImg:UIImage? = UIImage(data: imageData)
237 |
238 |
239 | for idx in 0...self.arrayResult.count-1
240 | {
241 | self.arrayResult[idx].imgScanned = scanImg
242 | }
243 | }
244 |
245 | self.successBlock(self.arrayResult)
246 |
247 | })
248 | }
249 |
250 | open func connectionWithMediaType(mediaType:AVMediaType,connections:[AnyObject]) -> AVCaptureConnection?
251 | {
252 | for connection:AnyObject in connections
253 | {
254 | let connectionTmp:AVCaptureConnection = connection as! AVCaptureConnection
255 |
256 | for port:Any in connectionTmp.inputPorts
257 | {
258 | if (port as AnyObject).isKind(of: AVCaptureInput.Port.self)
259 | {
260 | let portTmp:AVCaptureInput.Port = port as! AVCaptureInput.Port
261 | if portTmp.mediaType == mediaType
262 | {
263 | return connectionTmp
264 | }
265 | }
266 | }
267 | }
268 | return nil
269 | }
270 |
271 |
272 | //MARK:切换识别区域
273 | open func changeScanRect(cropRect:CGRect)
274 | {
275 | //待测试,不知道是否有效
276 | stop()
277 | output.rectOfInterest = cropRect
278 | start()
279 | }
280 |
281 | //MARK: 切换识别码的类型
282 | open func changeScanType(objType:[AVMetadataObject.ObjectType])
283 | {
284 | //待测试中途修改是否有效
285 | output.metadataObjectTypes = objType
286 | }
287 |
288 | open func isGetFlash()->Bool
289 | {
290 | if (device != nil && device!.hasFlash && device!.hasTorch)
291 | {
292 | return true
293 | }
294 | return false
295 | }
296 |
297 | /**
298 | 打开或关闭闪关灯
299 | - parameter torch: true:打开闪关灯 false:关闭闪光灯
300 | */
301 | open func setTorch(torch:Bool)
302 | {
303 | if isGetFlash()
304 | {
305 | do
306 | {
307 | try input?.device.lockForConfiguration()
308 |
309 | input?.device.torchMode = torch ? AVCaptureDevice.TorchMode.on : AVCaptureDevice.TorchMode.off
310 |
311 | input?.device.unlockForConfiguration()
312 | }
313 | catch let error as NSError {
314 | print("device.lockForConfiguration(): \(error)")
315 |
316 | }
317 | }
318 |
319 | }
320 |
321 |
322 | /**
323 | ------闪光灯打开或关闭
324 | */
325 | open func changeTorch()
326 | {
327 | if isGetFlash()
328 | {
329 | do
330 | {
331 | try input?.device.lockForConfiguration()
332 |
333 | var torch = false
334 |
335 | if input?.device.torchMode == AVCaptureDevice.TorchMode.on
336 | {
337 | torch = false
338 | }
339 | else if input?.device.torchMode == AVCaptureDevice.TorchMode.off
340 | {
341 | torch = true
342 | }
343 |
344 | input?.device.torchMode = torch ? AVCaptureDevice.TorchMode.on : AVCaptureDevice.TorchMode.off
345 |
346 | input?.device.unlockForConfiguration()
347 | }
348 | catch let error as NSError {
349 | print("device.lockForConfiguration(): \(error)")
350 |
351 | }
352 | }
353 | }
354 |
355 | //MARK: ------获取系统默认支持的码的类型
356 | static func defaultMetaDataObjectTypes() ->[AVMetadataObject.ObjectType]
357 | {
358 | var types =
359 | [AVMetadataObject.ObjectType.qr,
360 | AVMetadataObject.ObjectType.upce,
361 | AVMetadataObject.ObjectType.code39,
362 | AVMetadataObject.ObjectType.code39Mod43,
363 | AVMetadataObject.ObjectType.ean13,
364 | AVMetadataObject.ObjectType.ean8,
365 | AVMetadataObject.ObjectType.code93,
366 | AVMetadataObject.ObjectType.code128,
367 | AVMetadataObject.ObjectType.pdf417,
368 | AVMetadataObject.ObjectType.aztec,
369 |
370 | ];
371 | //if #available(iOS 8.0, *)
372 |
373 | types.append(AVMetadataObject.ObjectType.interleaved2of5)
374 | types.append(AVMetadataObject.ObjectType.itf14)
375 | types.append(AVMetadataObject.ObjectType.dataMatrix)
376 |
377 | types.append(AVMetadataObject.ObjectType.interleaved2of5)
378 | types.append(AVMetadataObject.ObjectType.itf14)
379 | types.append(AVMetadataObject.ObjectType.dataMatrix)
380 |
381 | return types as [AVMetadataObject.ObjectType];
382 | }
383 |
384 |
385 | static func isSysIos8Later()->Bool
386 | {
387 | // return floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_8_0
388 |
389 | if #available(iOS 8, *) {
390 | return true;
391 | }
392 | return false
393 | }
394 |
395 | /**
396 | 识别二维码码图像
397 |
398 | - parameter image: 二维码图像
399 |
400 | - returns: 返回识别结果
401 | */
402 | static public func recognizeQRImage(image:UIImage) ->[LBXScanResult]
403 | {
404 | var returnResult:[LBXScanResult]=[]
405 |
406 | if LBXScanWrapper.isSysIos8Later()
407 | {
408 | //if #available(iOS 8.0, *)
409 |
410 | let detector:CIDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])!
411 |
412 | let img = CIImage(cgImage: (image.cgImage)!)
413 |
414 | let features:[CIFeature]? = detector.features(in: img, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])
415 |
416 | if( features != nil && (features?.count)! > 0)
417 | {
418 | let feature = features![0]
419 |
420 | if feature.isKind(of: CIQRCodeFeature.self)
421 | {
422 | let featureTmp:CIQRCodeFeature = feature as! CIQRCodeFeature
423 |
424 | let scanResult = featureTmp.messageString
425 |
426 |
427 | let result = LBXScanResult(str: scanResult, img: image, barCodeType: AVMetadataObject.ObjectType.qr.rawValue,corner: nil)
428 |
429 | returnResult.append(result)
430 | }
431 | }
432 |
433 | }
434 |
435 | return returnResult
436 | }
437 |
438 |
439 | //MARK: -- - 生成二维码,背景色及二维码颜色设置
440 | static public func createCode( codeType:String, codeString:String, size:CGSize,qrColor:UIColor,bkColor:UIColor )->UIImage?
441 | {
442 | //if #available(iOS 8.0, *)
443 |
444 | let stringData = codeString.data(using: String.Encoding.utf8)
445 |
446 |
447 | //系统自带能生成的码
448 | // CIAztecCodeGenerator
449 | // CICode128BarcodeGenerator
450 | // CIPDF417BarcodeGenerator
451 | // CIQRCodeGenerator
452 | let qrFilter = CIFilter(name: codeType)
453 |
454 |
455 | qrFilter?.setValue(stringData, forKey: "inputMessage")
456 |
457 | qrFilter?.setValue("H", forKey: "inputCorrectionLevel")
458 |
459 |
460 | //上色
461 | let colorFilter = CIFilter(name: "CIFalseColor", parameters: ["inputImage":qrFilter!.outputImage!,"inputColor0":CIColor(cgColor: qrColor.cgColor),"inputColor1":CIColor(cgColor: bkColor.cgColor)])
462 |
463 |
464 | let qrImage = colorFilter!.outputImage!;
465 |
466 | //绘制
467 | let cgImage = CIContext().createCGImage(qrImage, from: qrImage.extent)!
468 |
469 |
470 | UIGraphicsBeginImageContext(size);
471 | let context = UIGraphicsGetCurrentContext()!;
472 | context.interpolationQuality = CGInterpolationQuality.none;
473 | context.scaleBy(x: 1.0, y: -1.0);
474 | context.draw(cgImage, in: context.boundingBoxOfClipPath)
475 | let codeImage = UIGraphicsGetImageFromCurrentImageContext();
476 | UIGraphicsEndImageContext();
477 |
478 | return codeImage
479 |
480 | }
481 |
482 | static public func createCode128( codeString:String, size:CGSize,qrColor:UIColor,bkColor:UIColor )->UIImage?
483 | {
484 | let stringData = codeString.data(using: String.Encoding.utf8)
485 |
486 |
487 | //系统自带能生成的码
488 | // CIAztecCodeGenerator 二维码
489 | // CICode128BarcodeGenerator 条形码
490 | // CIPDF417BarcodeGenerator
491 | // CIQRCodeGenerator 二维码
492 | let qrFilter = CIFilter(name: "CICode128BarcodeGenerator")
493 | qrFilter?.setDefaults()
494 | qrFilter?.setValue(stringData, forKey: "inputMessage")
495 |
496 |
497 |
498 | let outputImage:CIImage? = qrFilter?.outputImage
499 | let context = CIContext()
500 | let cgImage = context.createCGImage(outputImage!, from: outputImage!.extent)
501 |
502 | let image = UIImage(cgImage: cgImage!, scale: 1.0, orientation: UIImage.Orientation.up)
503 |
504 |
505 | // Resize without interpolating
506 | let scaleRate:CGFloat = 20.0
507 | let resized = resizeImage(image: image, quality: CGInterpolationQuality.none, rate: scaleRate)
508 |
509 | return resized;
510 | }
511 |
512 |
513 | //MARK:根据扫描结果,获取图像中得二维码区域图像(如果相机拍摄角度故意很倾斜,获取的图像效果很差)
514 | static func getConcreteCodeImage(srcCodeImage:UIImage,codeResult:LBXScanResult)->UIImage?
515 | {
516 | let rect:CGRect = getConcreteCodeRectFromImage(srcCodeImage: srcCodeImage, codeResult: codeResult)
517 |
518 | if rect.isEmpty
519 | {
520 | return nil
521 | }
522 |
523 | let img = imageByCroppingWithStyle(srcImg: srcCodeImage, rect: rect)
524 |
525 | if img != nil
526 | {
527 | let imgRotation = imageRotation(image: img!, orientation: UIImage.Orientation.right)
528 | return imgRotation
529 | }
530 | return nil
531 | }
532 | //根据二维码的区域截取二维码区域图像
533 | static public func getConcreteCodeImage(srcCodeImage:UIImage,rect:CGRect)->UIImage?
534 | {
535 | if rect.isEmpty
536 | {
537 | return nil
538 | }
539 |
540 | let img = imageByCroppingWithStyle(srcImg: srcCodeImage, rect: rect)
541 |
542 | if img != nil
543 | {
544 | let imgRotation = imageRotation(image: img!, orientation: UIImage.Orientation.right)
545 | return imgRotation
546 | }
547 | return nil
548 | }
549 |
550 | //获取二维码的图像区域
551 | static public func getConcreteCodeRectFromImage(srcCodeImage:UIImage,codeResult:LBXScanResult)->CGRect
552 | {
553 | if (codeResult.arrayCorner == nil || (codeResult.arrayCorner?.count)! < 4 )
554 | {
555 | return CGRect.zero
556 | }
557 |
558 | let corner:[[String:Float]] = codeResult.arrayCorner as! [[String:Float]]
559 |
560 | let dicTopLeft = corner[0]
561 | let dicTopRight = corner[1]
562 | let dicBottomRight = corner[2]
563 | let dicBottomLeft = corner[3]
564 |
565 | let xLeftTopRatio:Float = dicTopLeft["X"]!
566 | let yLeftTopRatio:Float = dicTopLeft["Y"]!
567 |
568 | let xRightTopRatio:Float = dicTopRight["X"]!
569 | let yRightTopRatio:Float = dicTopRight["Y"]!
570 |
571 | let xBottomRightRatio:Float = dicBottomRight["X"]!
572 | let yBottomRightRatio:Float = dicBottomRight["Y"]!
573 |
574 | let xLeftBottomRatio:Float = dicBottomLeft["X"]!
575 | let yLeftBottomRatio:Float = dicBottomLeft["Y"]!
576 |
577 | //由于截图只能矩形,所以截图不规则四边形的最大外围
578 | let xMinLeft = CGFloat( min(xLeftTopRatio, xLeftBottomRatio) )
579 | let xMaxRight = CGFloat( max(xRightTopRatio, xBottomRightRatio) )
580 |
581 | let yMinTop = CGFloat( min(yLeftTopRatio, yRightTopRatio) )
582 | let yMaxBottom = CGFloat ( max(yLeftBottomRatio, yBottomRightRatio) )
583 |
584 | let imgW = srcCodeImage.size.width
585 | let imgH = srcCodeImage.size.height
586 |
587 | //宽高反过来计算
588 | let rect = CGRect(x: xMinLeft * imgH, y: yMinTop*imgW, width: (xMaxRight-xMinLeft)*imgH, height: (yMaxBottom-yMinTop)*imgW)
589 | return rect
590 | }
591 |
592 | //MARK: ----图像处理
593 |
594 | /**
595 | @brief 图像中间加logo图片
596 | @param srcImg 原图像
597 | @param LogoImage logo图像
598 | @param logoSize logo图像尺寸
599 | @return 加Logo的图像
600 | */
601 | static public func addImageLogo(srcImg:UIImage,logoImg:UIImage,logoSize:CGSize )->UIImage
602 | {
603 | UIGraphicsBeginImageContext(srcImg.size);
604 | srcImg.draw(in: CGRect(x: 0, y: 0, width: srcImg.size.width, height: srcImg.size.height))
605 | let rect = CGRect(x: srcImg.size.width/2 - logoSize.width/2, y: srcImg.size.height/2-logoSize.height/2, width:logoSize.width, height: logoSize.height);
606 | logoImg.draw(in: rect)
607 | let resultingImage = UIGraphicsGetImageFromCurrentImageContext();
608 | UIGraphicsEndImageContext();
609 | return resultingImage!;
610 | }
611 |
612 | //图像缩放
613 | static func resizeImage(image:UIImage,quality:CGInterpolationQuality,rate:CGFloat)->UIImage?
614 | {
615 | var resized:UIImage?;
616 | let width = image.size.width * rate;
617 | let height = image.size.height * rate;
618 |
619 | UIGraphicsBeginImageContext(CGSize(width: width, height: height));
620 | let context = UIGraphicsGetCurrentContext();
621 | context!.interpolationQuality = quality;
622 | image.draw(in: CGRect(x: 0, y: 0, width: width, height: height))
623 |
624 | resized = UIGraphicsGetImageFromCurrentImageContext();
625 | UIGraphicsEndImageContext();
626 |
627 | return resized;
628 | }
629 |
630 |
631 | //图像裁剪
632 | static func imageByCroppingWithStyle(srcImg:UIImage,rect:CGRect)->UIImage?
633 | {
634 | let imageRef = srcImg.cgImage
635 | let imagePartRef = imageRef!.cropping(to: rect)
636 | let cropImage = UIImage(cgImage: imagePartRef!)
637 |
638 | return cropImage
639 | }
640 | //图像旋转
641 | static func imageRotation(image:UIImage,orientation:UIImage.Orientation)->UIImage
642 | {
643 | var rotate:Double = 0.0;
644 | var rect:CGRect;
645 | var translateX:CGFloat = 0.0;
646 | var translateY:CGFloat = 0.0;
647 | var scaleX:CGFloat = 1.0;
648 | var scaleY:CGFloat = 1.0;
649 |
650 | switch (orientation) {
651 | case UIImage.Orientation.left:
652 | rotate = .pi/2;
653 | rect = CGRect(x: 0, y: 0, width: image.size.height, height: image.size.width);
654 | translateX = 0;
655 | translateY = -rect.size.width;
656 | scaleY = rect.size.width/rect.size.height;
657 | scaleX = rect.size.height/rect.size.width;
658 | break;
659 | case UIImage.Orientation.right:
660 | rotate = 3 * .pi/2;
661 | rect = CGRect(x: 0, y: 0, width: image.size.height, height: image.size.width);
662 | translateX = -rect.size.height;
663 | translateY = 0;
664 | scaleY = rect.size.width/rect.size.height;
665 | scaleX = rect.size.height/rect.size.width;
666 | break;
667 | case UIImage.Orientation.down:
668 | rotate = .pi;
669 | rect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height);
670 | translateX = -rect.size.width;
671 | translateY = -rect.size.height;
672 | break;
673 | default:
674 | rotate = 0.0;
675 | rect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height);
676 | translateX = 0;
677 | translateY = 0;
678 | break;
679 | }
680 |
681 | UIGraphicsBeginImageContext(rect.size);
682 | let context = UIGraphicsGetCurrentContext()!;
683 | //做CTM变换
684 | context.translateBy(x: 0.0, y: rect.size.height);
685 | context.scaleBy(x: 1.0, y: -1.0);
686 | context.rotate(by: CGFloat(rotate));
687 | context.translateBy(x: translateX, y: translateY);
688 |
689 | context.scaleBy(x: scaleX, y: scaleY);
690 | //绘制图片
691 | context.draw(image.cgImage!, in: CGRect(x: 0, y: 0, width: rect.size.width, height: rect.size.height))
692 | let newPic = UIGraphicsGetImageFromCurrentImageContext();
693 |
694 | return newPic!;
695 | }
696 |
697 | deinit
698 | {
699 | // print("LBXScanWrapper deinit")
700 | }
701 |
702 |
703 |
704 | }
705 |
--------------------------------------------------------------------------------
/GTMWebKit.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 48;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2619000321477FFC00B2C31C /* GTMWebKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2619000221477FFC00B2C31C /* GTMWebKit.swift */; };
11 | 2657A3AB1FA993C200A717A3 /* GTMWebKit.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 2657A3A41FA993C100A717A3 /* GTMWebKit.bundle */; };
12 | 2657A3AC1FA993C200A717A3 /* GTMAlertable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2657A3A51FA993C100A717A3 /* GTMAlertable.swift */; };
13 | 2657A3AD1FA993C200A717A3 /* GTMWebView+Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2657A3A61FA993C200A717A3 /* GTMWebView+Alert.swift */; };
14 | 2657A3AE1FA993C200A717A3 /* GTMWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2657A3A71FA993C200A717A3 /* GTMWebViewController.swift */; };
15 | 2657A3AF1FA993C200A717A3 /* GTMWebView+Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2657A3A81FA993C200A717A3 /* GTMWebView+Bundle.swift */; };
16 | 2657A3B01FA993C200A717A3 /* URLConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2657A3A91FA993C200A717A3 /* URLConvertible.swift */; };
17 | 2657A3B11FA993C200A717A3 /* WeakScriptMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2657A3AA1FA993C200A717A3 /* WeakScriptMessageHandler.swift */; };
18 | 2657A3B91FA993EA00A717A3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2657A3B81FA993EA00A717A3 /* AppDelegate.swift */; };
19 | 2657A3BB1FA993EA00A717A3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2657A3BA1FA993EA00A717A3 /* ViewController.swift */; };
20 | 2657A3BE1FA993EA00A717A3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2657A3BC1FA993EA00A717A3 /* Main.storyboard */; };
21 | 2657A3C01FA993EA00A717A3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2657A3BF1FA993EA00A717A3 /* Assets.xcassets */; };
22 | 2657A3C31FA993EA00A717A3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2657A3C11FA993EA00A717A3 /* LaunchScreen.storyboard */; };
23 | 2657A3C91FA994BE00A717A3 /* test.html in Resources */ = {isa = PBXBuildFile; fileRef = 2657A3C81FA994BE00A717A3 /* test.html */; };
24 | 2657A3CA1FA994FD00A717A3 /* GTMWebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2657A3991FA9939300A717A3 /* GTMWebKit.framework */; };
25 | 2657A3CB1FA994FD00A717A3 /* GTMWebKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 2657A3991FA9939300A717A3 /* GTMWebKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
26 | 2657A3D41FA9BC7600A717A3 /* CustomWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2657A3D31FA9BC7600A717A3 /* CustomWebViewController.swift */; };
27 | 26712C6B1FAABF3900AC3255 /* LBXPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26712C641FAABF3800AC3255 /* LBXPermissions.swift */; };
28 | 26712C6C1FAABF3900AC3255 /* LBXScanLineAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26712C651FAABF3800AC3255 /* LBXScanLineAnimation.swift */; };
29 | 26712C6D1FAABF3900AC3255 /* LBXScanNetAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26712C661FAABF3800AC3255 /* LBXScanNetAnimation.swift */; };
30 | 26712C6E1FAABF3900AC3255 /* LBXScanView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26712C671FAABF3800AC3255 /* LBXScanView.swift */; };
31 | 26712C6F1FAABF3900AC3255 /* LBXScanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26712C681FAABF3800AC3255 /* LBXScanViewController.swift */; };
32 | 26712C701FAABF3900AC3255 /* LBXScanViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26712C691FAABF3800AC3255 /* LBXScanViewStyle.swift */; };
33 | 26712C711FAABF3900AC3255 /* LBXScanWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26712C6A1FAABF3800AC3255 /* LBXScanWrapper.swift */; };
34 | 26712C731FAABFC100AC3255 /* BarcodeScanable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26712C721FAABFC100AC3255 /* BarcodeScanable.swift */; };
35 | 26712C751FAAC03200AC3255 /* ScanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26712C741FAAC03200AC3255 /* ScanViewController.swift */; };
36 | 26712C7B1FAAE8D600AC3255 /* GTMWebKit.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 26712C781FAAE8D500AC3255 /* GTMWebKit.podspec */; };
37 | 26712C7C1FAAE8D600AC3255 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 26712C791FAAE8D500AC3255 /* LICENSE */; };
38 | 26712C7D1FAAE8D600AC3255 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 26712C7A1FAAE8D500AC3255 /* README.md */; };
39 | 26712C811FAAF30000AC3255 /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = 26712C801FAAF30000AC3255 /* logo.png */; };
40 | 26B891F61FB3E5AF00EC7251 /* GTMWebView+WKWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B891F51FB3E5AF00EC7251 /* GTMWebView+WKWebView.swift */; };
41 | 26C629162193FCD200AC5F42 /* GTMWebControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26C629152193FCD200AC5F42 /* GTMWebControls.swift */; };
42 | 26DDD6E51FBD588A0029EA3F /* UIWebViewCookiesVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DDD6E41FBD588A0029EA3F /* UIWebViewCookiesVC.swift */; };
43 | 26DDD6E71FBD589B0029EA3F /* WKWebViewCookiesVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DDD6E61FBD589B0029EA3F /* WKWebViewCookiesVC.swift */; };
44 | 26DDD6EB1FBD8CE50029EA3F /* GTMWebViewCookies.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DDD6EA1FBD8CE50029EA3F /* GTMWebViewCookies.swift */; };
45 | /* End PBXBuildFile section */
46 |
47 | /* Begin PBXContainerItemProxy section */
48 | 2657A3CC1FA994FD00A717A3 /* PBXContainerItemProxy */ = {
49 | isa = PBXContainerItemProxy;
50 | containerPortal = 2657A3901FA9939300A717A3 /* Project object */;
51 | proxyType = 1;
52 | remoteGlobalIDString = 2657A3981FA9939300A717A3;
53 | remoteInfo = GTMWebKit;
54 | };
55 | /* End PBXContainerItemProxy section */
56 |
57 | /* Begin PBXCopyFilesBuildPhase section */
58 | 2657A3CE1FA994FD00A717A3 /* Embed Frameworks */ = {
59 | isa = PBXCopyFilesBuildPhase;
60 | buildActionMask = 2147483647;
61 | dstPath = "";
62 | dstSubfolderSpec = 10;
63 | files = (
64 | 2657A3CB1FA994FD00A717A3 /* GTMWebKit.framework in Embed Frameworks */,
65 | );
66 | name = "Embed Frameworks";
67 | runOnlyForDeploymentPostprocessing = 0;
68 | };
69 | /* End PBXCopyFilesBuildPhase section */
70 |
71 | /* Begin PBXFileReference section */
72 | 2619000221477FFC00B2C31C /* GTMWebKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GTMWebKit.swift; sourceTree = ""; };
73 | 2657A3991FA9939300A717A3 /* GTMWebKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GTMWebKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
74 | 2657A39D1FA9939300A717A3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
75 | 2657A3A41FA993C100A717A3 /* GTMWebKit.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = GTMWebKit.bundle; sourceTree = ""; };
76 | 2657A3A51FA993C100A717A3 /* GTMAlertable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GTMAlertable.swift; sourceTree = ""; };
77 | 2657A3A61FA993C200A717A3 /* GTMWebView+Alert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GTMWebView+Alert.swift"; sourceTree = ""; };
78 | 2657A3A71FA993C200A717A3 /* GTMWebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GTMWebViewController.swift; sourceTree = ""; };
79 | 2657A3A81FA993C200A717A3 /* GTMWebView+Bundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GTMWebView+Bundle.swift"; sourceTree = ""; };
80 | 2657A3A91FA993C200A717A3 /* URLConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLConvertible.swift; sourceTree = ""; };
81 | 2657A3AA1FA993C200A717A3 /* WeakScriptMessageHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakScriptMessageHandler.swift; sourceTree = ""; };
82 | 2657A3B61FA993EA00A717A3 /* GTMWebKitExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GTMWebKitExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
83 | 2657A3B81FA993EA00A717A3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
84 | 2657A3BA1FA993EA00A717A3 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
85 | 2657A3BD1FA993EA00A717A3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
86 | 2657A3BF1FA993EA00A717A3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
87 | 2657A3C21FA993EA00A717A3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
88 | 2657A3C41FA993EA00A717A3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
89 | 2657A3C81FA994BE00A717A3 /* test.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = test.html; sourceTree = ""; };
90 | 2657A3CF1FA9952900A717A3 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Main.strings"; sourceTree = ""; };
91 | 2657A3D01FA9952900A717A3 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/LaunchScreen.strings"; sourceTree = ""; };
92 | 2657A3D31FA9BC7600A717A3 /* CustomWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomWebViewController.swift; sourceTree = ""; };
93 | 26712C641FAABF3800AC3255 /* LBXPermissions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXPermissions.swift; sourceTree = ""; };
94 | 26712C651FAABF3800AC3255 /* LBXScanLineAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanLineAnimation.swift; sourceTree = ""; };
95 | 26712C661FAABF3800AC3255 /* LBXScanNetAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanNetAnimation.swift; sourceTree = ""; };
96 | 26712C671FAABF3800AC3255 /* LBXScanView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanView.swift; sourceTree = ""; };
97 | 26712C681FAABF3800AC3255 /* LBXScanViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanViewController.swift; sourceTree = ""; };
98 | 26712C691FAABF3800AC3255 /* LBXScanViewStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanViewStyle.swift; sourceTree = ""; };
99 | 26712C6A1FAABF3800AC3255 /* LBXScanWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanWrapper.swift; sourceTree = ""; };
100 | 26712C721FAABFC100AC3255 /* BarcodeScanable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarcodeScanable.swift; sourceTree = ""; };
101 | 26712C741FAAC03200AC3255 /* ScanViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanViewController.swift; sourceTree = ""; };
102 | 26712C781FAAE8D500AC3255 /* GTMWebKit.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GTMWebKit.podspec; sourceTree = ""; };
103 | 26712C791FAAE8D500AC3255 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; };
104 | 26712C7A1FAAE8D500AC3255 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
105 | 26712C801FAAF30000AC3255 /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo.png; sourceTree = ""; };
106 | 26B891F51FB3E5AF00EC7251 /* GTMWebView+WKWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GTMWebView+WKWebView.swift"; sourceTree = ""; };
107 | 26C629152193FCD200AC5F42 /* GTMWebControls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GTMWebControls.swift; sourceTree = ""; };
108 | 26DDD6E41FBD588A0029EA3F /* UIWebViewCookiesVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIWebViewCookiesVC.swift; sourceTree = ""; };
109 | 26DDD6E61FBD589B0029EA3F /* WKWebViewCookiesVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKWebViewCookiesVC.swift; sourceTree = ""; };
110 | 26DDD6EA1FBD8CE50029EA3F /* GTMWebViewCookies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GTMWebViewCookies.swift; sourceTree = ""; };
111 | /* End PBXFileReference section */
112 |
113 | /* Begin PBXFrameworksBuildPhase section */
114 | 2657A3951FA9939300A717A3 /* Frameworks */ = {
115 | isa = PBXFrameworksBuildPhase;
116 | buildActionMask = 2147483647;
117 | files = (
118 | );
119 | runOnlyForDeploymentPostprocessing = 0;
120 | };
121 | 2657A3B31FA993EA00A717A3 /* Frameworks */ = {
122 | isa = PBXFrameworksBuildPhase;
123 | buildActionMask = 2147483647;
124 | files = (
125 | 2657A3CA1FA994FD00A717A3 /* GTMWebKit.framework in Frameworks */,
126 | );
127 | runOnlyForDeploymentPostprocessing = 0;
128 | };
129 | /* End PBXFrameworksBuildPhase section */
130 |
131 | /* Begin PBXGroup section */
132 | 262656921FBC32E500681044 /* Cookies */ = {
133 | isa = PBXGroup;
134 | children = (
135 | 26DDD6E41FBD588A0029EA3F /* UIWebViewCookiesVC.swift */,
136 | 26DDD6E61FBD589B0029EA3F /* WKWebViewCookiesVC.swift */,
137 | );
138 | name = Cookies;
139 | sourceTree = "";
140 | };
141 | 2657A38F1FA9939300A717A3 = {
142 | isa = PBXGroup;
143 | children = (
144 | 26712C801FAAF30000AC3255 /* logo.png */,
145 | 26712C781FAAE8D500AC3255 /* GTMWebKit.podspec */,
146 | 26712C791FAAE8D500AC3255 /* LICENSE */,
147 | 26712C7A1FAAE8D500AC3255 /* README.md */,
148 | 2657A39B1FA9939300A717A3 /* GTMWebKit */,
149 | 2657A3B71FA993EA00A717A3 /* GTMWebKitExample */,
150 | 2657A39A1FA9939300A717A3 /* Products */,
151 | );
152 | sourceTree = "";
153 | };
154 | 2657A39A1FA9939300A717A3 /* Products */ = {
155 | isa = PBXGroup;
156 | children = (
157 | 2657A3991FA9939300A717A3 /* GTMWebKit.framework */,
158 | 2657A3B61FA993EA00A717A3 /* GTMWebKitExample.app */,
159 | );
160 | name = Products;
161 | sourceTree = "";
162 | };
163 | 2657A39B1FA9939300A717A3 /* GTMWebKit */ = {
164 | isa = PBXGroup;
165 | children = (
166 | 2619000221477FFC00B2C31C /* GTMWebKit.swift */,
167 | 26C629152193FCD200AC5F42 /* GTMWebControls.swift */,
168 | 2657A3A51FA993C100A717A3 /* GTMAlertable.swift */,
169 | 2657A3A61FA993C200A717A3 /* GTMWebView+Alert.swift */,
170 | 2657A3A81FA993C200A717A3 /* GTMWebView+Bundle.swift */,
171 | 26B891F51FB3E5AF00EC7251 /* GTMWebView+WKWebView.swift */,
172 | 26DDD6EA1FBD8CE50029EA3F /* GTMWebViewCookies.swift */,
173 | 2657A3A71FA993C200A717A3 /* GTMWebViewController.swift */,
174 | 2657A3A91FA993C200A717A3 /* URLConvertible.swift */,
175 | 2657A3AA1FA993C200A717A3 /* WeakScriptMessageHandler.swift */,
176 | 2657A3D11FA9958D00A717A3 /* Supporting Files */,
177 | );
178 | path = GTMWebKit;
179 | sourceTree = "";
180 | };
181 | 2657A3B71FA993EA00A717A3 /* GTMWebKitExample */ = {
182 | isa = PBXGroup;
183 | children = (
184 | 262656921FBC32E500681044 /* Cookies */,
185 | 26712C771FAAC06000AC3255 /* Native And JS */,
186 | 26712C761FAAC04100AC3255 /* Barcode Scan */,
187 | 2657A3B81FA993EA00A717A3 /* AppDelegate.swift */,
188 | 2657A3BA1FA993EA00A717A3 /* ViewController.swift */,
189 | 2657A3D21FA995CA00A717A3 /* Supporting Files */,
190 | );
191 | path = GTMWebKitExample;
192 | sourceTree = "";
193 | };
194 | 2657A3D11FA9958D00A717A3 /* Supporting Files */ = {
195 | isa = PBXGroup;
196 | children = (
197 | 2657A39D1FA9939300A717A3 /* Info.plist */,
198 | 2657A3A41FA993C100A717A3 /* GTMWebKit.bundle */,
199 | );
200 | name = "Supporting Files";
201 | sourceTree = "";
202 | };
203 | 2657A3D21FA995CA00A717A3 /* Supporting Files */ = {
204 | isa = PBXGroup;
205 | children = (
206 | 2657A3BC1FA993EA00A717A3 /* Main.storyboard */,
207 | 2657A3C11FA993EA00A717A3 /* LaunchScreen.storyboard */,
208 | 2657A3BF1FA993EA00A717A3 /* Assets.xcassets */,
209 | 2657A3C81FA994BE00A717A3 /* test.html */,
210 | 2657A3C41FA993EA00A717A3 /* Info.plist */,
211 | );
212 | name = "Supporting Files";
213 | sourceTree = "";
214 | };
215 | 26712C631FAABF3800AC3255 /* Swift Scan */ = {
216 | isa = PBXGroup;
217 | children = (
218 | 26712C641FAABF3800AC3255 /* LBXPermissions.swift */,
219 | 26712C651FAABF3800AC3255 /* LBXScanLineAnimation.swift */,
220 | 26712C661FAABF3800AC3255 /* LBXScanNetAnimation.swift */,
221 | 26712C671FAABF3800AC3255 /* LBXScanView.swift */,
222 | 26712C681FAABF3800AC3255 /* LBXScanViewController.swift */,
223 | 26712C691FAABF3800AC3255 /* LBXScanViewStyle.swift */,
224 | 26712C6A1FAABF3800AC3255 /* LBXScanWrapper.swift */,
225 | );
226 | path = "Swift Scan";
227 | sourceTree = "";
228 | };
229 | 26712C761FAAC04100AC3255 /* Barcode Scan */ = {
230 | isa = PBXGroup;
231 | children = (
232 | 26712C741FAAC03200AC3255 /* ScanViewController.swift */,
233 | 26712C721FAABFC100AC3255 /* BarcodeScanable.swift */,
234 | 26712C631FAABF3800AC3255 /* Swift Scan */,
235 | );
236 | name = "Barcode Scan";
237 | sourceTree = "";
238 | };
239 | 26712C771FAAC06000AC3255 /* Native And JS */ = {
240 | isa = PBXGroup;
241 | children = (
242 | 2657A3D31FA9BC7600A717A3 /* CustomWebViewController.swift */,
243 | );
244 | name = "Native And JS";
245 | sourceTree = "";
246 | };
247 | /* End PBXGroup section */
248 |
249 | /* Begin PBXHeadersBuildPhase section */
250 | 2657A3961FA9939300A717A3 /* Headers */ = {
251 | isa = PBXHeadersBuildPhase;
252 | buildActionMask = 2147483647;
253 | files = (
254 | );
255 | runOnlyForDeploymentPostprocessing = 0;
256 | };
257 | /* End PBXHeadersBuildPhase section */
258 |
259 | /* Begin PBXNativeTarget section */
260 | 2657A3981FA9939300A717A3 /* GTMWebKit */ = {
261 | isa = PBXNativeTarget;
262 | buildConfigurationList = 2657A3A11FA9939300A717A3 /* Build configuration list for PBXNativeTarget "GTMWebKit" */;
263 | buildPhases = (
264 | 2657A3941FA9939300A717A3 /* Sources */,
265 | 2657A3951FA9939300A717A3 /* Frameworks */,
266 | 2657A3961FA9939300A717A3 /* Headers */,
267 | 2657A3971FA9939300A717A3 /* Resources */,
268 | );
269 | buildRules = (
270 | );
271 | dependencies = (
272 | );
273 | name = GTMWebKit;
274 | productName = GTMWebKit;
275 | productReference = 2657A3991FA9939300A717A3 /* GTMWebKit.framework */;
276 | productType = "com.apple.product-type.framework";
277 | };
278 | 2657A3B51FA993EA00A717A3 /* GTMWebKitExample */ = {
279 | isa = PBXNativeTarget;
280 | buildConfigurationList = 2657A3C51FA993EA00A717A3 /* Build configuration list for PBXNativeTarget "GTMWebKitExample" */;
281 | buildPhases = (
282 | 2657A3B21FA993EA00A717A3 /* Sources */,
283 | 2657A3B31FA993EA00A717A3 /* Frameworks */,
284 | 2657A3B41FA993EA00A717A3 /* Resources */,
285 | 2657A3CE1FA994FD00A717A3 /* Embed Frameworks */,
286 | );
287 | buildRules = (
288 | );
289 | dependencies = (
290 | 2657A3CD1FA994FD00A717A3 /* PBXTargetDependency */,
291 | );
292 | name = GTMWebKitExample;
293 | productName = GTMWebKitExample;
294 | productReference = 2657A3B61FA993EA00A717A3 /* GTMWebKitExample.app */;
295 | productType = "com.apple.product-type.application";
296 | };
297 | /* End PBXNativeTarget section */
298 |
299 | /* Begin PBXProject section */
300 | 2657A3901FA9939300A717A3 /* Project object */ = {
301 | isa = PBXProject;
302 | attributes = {
303 | LastSwiftUpdateCheck = 0900;
304 | LastUpgradeCheck = 0900;
305 | ORGANIZATIONNAME = yang;
306 | TargetAttributes = {
307 | 2657A3981FA9939300A717A3 = {
308 | CreatedOnToolsVersion = 9.0.1;
309 | LastSwiftMigration = 0900;
310 | ProvisioningStyle = Automatic;
311 | };
312 | 2657A3B51FA993EA00A717A3 = {
313 | CreatedOnToolsVersion = 9.0.1;
314 | ProvisioningStyle = Automatic;
315 | };
316 | };
317 | };
318 | buildConfigurationList = 2657A3931FA9939300A717A3 /* Build configuration list for PBXProject "GTMWebKit" */;
319 | compatibilityVersion = "Xcode 8.0";
320 | developmentRegion = en;
321 | hasScannedForEncodings = 0;
322 | knownRegions = (
323 | en,
324 | Base,
325 | );
326 | mainGroup = 2657A38F1FA9939300A717A3;
327 | productRefGroup = 2657A39A1FA9939300A717A3 /* Products */;
328 | projectDirPath = "";
329 | projectRoot = "";
330 | targets = (
331 | 2657A3981FA9939300A717A3 /* GTMWebKit */,
332 | 2657A3B51FA993EA00A717A3 /* GTMWebKitExample */,
333 | );
334 | };
335 | /* End PBXProject section */
336 |
337 | /* Begin PBXResourcesBuildPhase section */
338 | 2657A3971FA9939300A717A3 /* Resources */ = {
339 | isa = PBXResourcesBuildPhase;
340 | buildActionMask = 2147483647;
341 | files = (
342 | 2657A3AB1FA993C200A717A3 /* GTMWebKit.bundle in Resources */,
343 | );
344 | runOnlyForDeploymentPostprocessing = 0;
345 | };
346 | 2657A3B41FA993EA00A717A3 /* Resources */ = {
347 | isa = PBXResourcesBuildPhase;
348 | buildActionMask = 2147483647;
349 | files = (
350 | 26712C7C1FAAE8D600AC3255 /* LICENSE in Resources */,
351 | 2657A3C91FA994BE00A717A3 /* test.html in Resources */,
352 | 26712C7B1FAAE8D600AC3255 /* GTMWebKit.podspec in Resources */,
353 | 26712C7D1FAAE8D600AC3255 /* README.md in Resources */,
354 | 26712C811FAAF30000AC3255 /* logo.png in Resources */,
355 | 2657A3C31FA993EA00A717A3 /* LaunchScreen.storyboard in Resources */,
356 | 2657A3C01FA993EA00A717A3 /* Assets.xcassets in Resources */,
357 | 2657A3BE1FA993EA00A717A3 /* Main.storyboard in Resources */,
358 | );
359 | runOnlyForDeploymentPostprocessing = 0;
360 | };
361 | /* End PBXResourcesBuildPhase section */
362 |
363 | /* Begin PBXSourcesBuildPhase section */
364 | 2657A3941FA9939300A717A3 /* Sources */ = {
365 | isa = PBXSourcesBuildPhase;
366 | buildActionMask = 2147483647;
367 | files = (
368 | 26B891F61FB3E5AF00EC7251 /* GTMWebView+WKWebView.swift in Sources */,
369 | 2657A3AF1FA993C200A717A3 /* GTMWebView+Bundle.swift in Sources */,
370 | 2657A3B11FA993C200A717A3 /* WeakScriptMessageHandler.swift in Sources */,
371 | 2657A3AC1FA993C200A717A3 /* GTMAlertable.swift in Sources */,
372 | 2657A3AE1FA993C200A717A3 /* GTMWebViewController.swift in Sources */,
373 | 26C629162193FCD200AC5F42 /* GTMWebControls.swift in Sources */,
374 | 2619000321477FFC00B2C31C /* GTMWebKit.swift in Sources */,
375 | 26DDD6EB1FBD8CE50029EA3F /* GTMWebViewCookies.swift in Sources */,
376 | 2657A3AD1FA993C200A717A3 /* GTMWebView+Alert.swift in Sources */,
377 | 2657A3B01FA993C200A717A3 /* URLConvertible.swift in Sources */,
378 | );
379 | runOnlyForDeploymentPostprocessing = 0;
380 | };
381 | 2657A3B21FA993EA00A717A3 /* Sources */ = {
382 | isa = PBXSourcesBuildPhase;
383 | buildActionMask = 2147483647;
384 | files = (
385 | 26712C6F1FAABF3900AC3255 /* LBXScanViewController.swift in Sources */,
386 | 26712C711FAABF3900AC3255 /* LBXScanWrapper.swift in Sources */,
387 | 26712C731FAABFC100AC3255 /* BarcodeScanable.swift in Sources */,
388 | 26712C6C1FAABF3900AC3255 /* LBXScanLineAnimation.swift in Sources */,
389 | 26712C6E1FAABF3900AC3255 /* LBXScanView.swift in Sources */,
390 | 2657A3BB1FA993EA00A717A3 /* ViewController.swift in Sources */,
391 | 26712C6B1FAABF3900AC3255 /* LBXPermissions.swift in Sources */,
392 | 26712C701FAABF3900AC3255 /* LBXScanViewStyle.swift in Sources */,
393 | 2657A3B91FA993EA00A717A3 /* AppDelegate.swift in Sources */,
394 | 26712C6D1FAABF3900AC3255 /* LBXScanNetAnimation.swift in Sources */,
395 | 2657A3D41FA9BC7600A717A3 /* CustomWebViewController.swift in Sources */,
396 | 26712C751FAAC03200AC3255 /* ScanViewController.swift in Sources */,
397 | 26DDD6E51FBD588A0029EA3F /* UIWebViewCookiesVC.swift in Sources */,
398 | 26DDD6E71FBD589B0029EA3F /* WKWebViewCookiesVC.swift in Sources */,
399 | );
400 | runOnlyForDeploymentPostprocessing = 0;
401 | };
402 | /* End PBXSourcesBuildPhase section */
403 |
404 | /* Begin PBXTargetDependency section */
405 | 2657A3CD1FA994FD00A717A3 /* PBXTargetDependency */ = {
406 | isa = PBXTargetDependency;
407 | target = 2657A3981FA9939300A717A3 /* GTMWebKit */;
408 | targetProxy = 2657A3CC1FA994FD00A717A3 /* PBXContainerItemProxy */;
409 | };
410 | /* End PBXTargetDependency section */
411 |
412 | /* Begin PBXVariantGroup section */
413 | 2657A3BC1FA993EA00A717A3 /* Main.storyboard */ = {
414 | isa = PBXVariantGroup;
415 | children = (
416 | 2657A3BD1FA993EA00A717A3 /* Base */,
417 | 2657A3CF1FA9952900A717A3 /* zh-Hans */,
418 | );
419 | name = Main.storyboard;
420 | sourceTree = "";
421 | };
422 | 2657A3C11FA993EA00A717A3 /* LaunchScreen.storyboard */ = {
423 | isa = PBXVariantGroup;
424 | children = (
425 | 2657A3C21FA993EA00A717A3 /* Base */,
426 | 2657A3D01FA9952900A717A3 /* zh-Hans */,
427 | );
428 | name = LaunchScreen.storyboard;
429 | sourceTree = "";
430 | };
431 | /* End PBXVariantGroup section */
432 |
433 | /* Begin XCBuildConfiguration section */
434 | 2657A39F1FA9939300A717A3 /* Debug */ = {
435 | isa = XCBuildConfiguration;
436 | buildSettings = {
437 | ALWAYS_SEARCH_USER_PATHS = NO;
438 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
439 | CLANG_ANALYZER_NONNULL = YES;
440 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
441 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
442 | CLANG_CXX_LIBRARY = "libc++";
443 | CLANG_ENABLE_MODULES = YES;
444 | CLANG_ENABLE_OBJC_ARC = YES;
445 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
446 | CLANG_WARN_BOOL_CONVERSION = YES;
447 | CLANG_WARN_COMMA = YES;
448 | CLANG_WARN_CONSTANT_CONVERSION = YES;
449 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
450 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
451 | CLANG_WARN_EMPTY_BODY = YES;
452 | CLANG_WARN_ENUM_CONVERSION = YES;
453 | CLANG_WARN_INFINITE_RECURSION = YES;
454 | CLANG_WARN_INT_CONVERSION = YES;
455 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
456 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
457 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
458 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
459 | CLANG_WARN_STRICT_PROTOTYPES = YES;
460 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
461 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
462 | CLANG_WARN_UNREACHABLE_CODE = YES;
463 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
464 | CODE_SIGN_IDENTITY = "iPhone Developer";
465 | COPY_PHASE_STRIP = NO;
466 | CURRENT_PROJECT_VERSION = 1;
467 | DEBUG_INFORMATION_FORMAT = dwarf;
468 | ENABLE_STRICT_OBJC_MSGSEND = YES;
469 | ENABLE_TESTABILITY = YES;
470 | GCC_C_LANGUAGE_STANDARD = gnu11;
471 | GCC_DYNAMIC_NO_PIC = NO;
472 | GCC_NO_COMMON_BLOCKS = YES;
473 | GCC_OPTIMIZATION_LEVEL = 0;
474 | GCC_PREPROCESSOR_DEFINITIONS = (
475 | "DEBUG=1",
476 | "$(inherited)",
477 | );
478 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
479 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
480 | GCC_WARN_UNDECLARED_SELECTOR = YES;
481 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
482 | GCC_WARN_UNUSED_FUNCTION = YES;
483 | GCC_WARN_UNUSED_VARIABLE = YES;
484 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
485 | MTL_ENABLE_DEBUG_INFO = YES;
486 | ONLY_ACTIVE_ARCH = YES;
487 | SDKROOT = iphoneos;
488 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
489 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
490 | SWIFT_VERSION = 4.2;
491 | VERSIONING_SYSTEM = "apple-generic";
492 | VERSION_INFO_PREFIX = "";
493 | };
494 | name = Debug;
495 | };
496 | 2657A3A01FA9939300A717A3 /* Release */ = {
497 | isa = XCBuildConfiguration;
498 | buildSettings = {
499 | ALWAYS_SEARCH_USER_PATHS = NO;
500 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
501 | CLANG_ANALYZER_NONNULL = YES;
502 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
503 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
504 | CLANG_CXX_LIBRARY = "libc++";
505 | CLANG_ENABLE_MODULES = YES;
506 | CLANG_ENABLE_OBJC_ARC = YES;
507 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
508 | CLANG_WARN_BOOL_CONVERSION = YES;
509 | CLANG_WARN_COMMA = YES;
510 | CLANG_WARN_CONSTANT_CONVERSION = YES;
511 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
512 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
513 | CLANG_WARN_EMPTY_BODY = YES;
514 | CLANG_WARN_ENUM_CONVERSION = YES;
515 | CLANG_WARN_INFINITE_RECURSION = YES;
516 | CLANG_WARN_INT_CONVERSION = YES;
517 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
518 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
519 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
520 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
521 | CLANG_WARN_STRICT_PROTOTYPES = YES;
522 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
523 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
524 | CLANG_WARN_UNREACHABLE_CODE = YES;
525 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
526 | CODE_SIGN_IDENTITY = "iPhone Developer";
527 | COPY_PHASE_STRIP = NO;
528 | CURRENT_PROJECT_VERSION = 1;
529 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
530 | ENABLE_NS_ASSERTIONS = NO;
531 | ENABLE_STRICT_OBJC_MSGSEND = YES;
532 | GCC_C_LANGUAGE_STANDARD = gnu11;
533 | GCC_NO_COMMON_BLOCKS = YES;
534 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
535 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
536 | GCC_WARN_UNDECLARED_SELECTOR = YES;
537 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
538 | GCC_WARN_UNUSED_FUNCTION = YES;
539 | GCC_WARN_UNUSED_VARIABLE = YES;
540 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
541 | MTL_ENABLE_DEBUG_INFO = NO;
542 | SDKROOT = iphoneos;
543 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
544 | SWIFT_VERSION = 4.2;
545 | VALIDATE_PRODUCT = YES;
546 | VERSIONING_SYSTEM = "apple-generic";
547 | VERSION_INFO_PREFIX = "";
548 | };
549 | name = Release;
550 | };
551 | 2657A3A21FA9939300A717A3 /* Debug */ = {
552 | isa = XCBuildConfiguration;
553 | buildSettings = {
554 | CLANG_ENABLE_MODULES = YES;
555 | CODE_SIGN_IDENTITY = "";
556 | CODE_SIGN_STYLE = Automatic;
557 | DEFINES_MODULE = YES;
558 | DEVELOPMENT_TEAM = 2DUPQ924JY;
559 | DYLIB_COMPATIBILITY_VERSION = 1;
560 | DYLIB_CURRENT_VERSION = 1;
561 | DYLIB_INSTALL_NAME_BASE = "@rpath";
562 | INFOPLIST_FILE = GTMWebKit/Info.plist;
563 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
564 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
565 | PRODUCT_BUNDLE_IDENTIFIER = com.yang.GTMWebKit;
566 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
567 | SKIP_INSTALL = YES;
568 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
569 | SWIFT_VERSION = 4.2;
570 | TARGETED_DEVICE_FAMILY = "1,2";
571 | };
572 | name = Debug;
573 | };
574 | 2657A3A31FA9939300A717A3 /* Release */ = {
575 | isa = XCBuildConfiguration;
576 | buildSettings = {
577 | CLANG_ENABLE_MODULES = YES;
578 | CODE_SIGN_IDENTITY = "";
579 | CODE_SIGN_STYLE = Automatic;
580 | DEFINES_MODULE = YES;
581 | DEVELOPMENT_TEAM = 2DUPQ924JY;
582 | DYLIB_COMPATIBILITY_VERSION = 1;
583 | DYLIB_CURRENT_VERSION = 1;
584 | DYLIB_INSTALL_NAME_BASE = "@rpath";
585 | INFOPLIST_FILE = GTMWebKit/Info.plist;
586 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
587 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
588 | PRODUCT_BUNDLE_IDENTIFIER = com.yang.GTMWebKit;
589 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
590 | SKIP_INSTALL = YES;
591 | SWIFT_VERSION = 4.2;
592 | TARGETED_DEVICE_FAMILY = "1,2";
593 | };
594 | name = Release;
595 | };
596 | 2657A3C61FA993EA00A717A3 /* Debug */ = {
597 | isa = XCBuildConfiguration;
598 | buildSettings = {
599 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
600 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
601 | CODE_SIGN_STYLE = Automatic;
602 | DEVELOPMENT_TEAM = 2DUPQ924JY;
603 | INFOPLIST_FILE = GTMWebKitExample/Info.plist;
604 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
605 | PRODUCT_BUNDLE_IDENTIFIER = com.yang.GTMWebKitExample;
606 | PRODUCT_NAME = "$(TARGET_NAME)";
607 | SWIFT_VERSION = 4.2;
608 | TARGETED_DEVICE_FAMILY = 1;
609 | };
610 | name = Debug;
611 | };
612 | 2657A3C71FA993EA00A717A3 /* Release */ = {
613 | isa = XCBuildConfiguration;
614 | buildSettings = {
615 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
616 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
617 | CODE_SIGN_STYLE = Automatic;
618 | DEVELOPMENT_TEAM = 2DUPQ924JY;
619 | INFOPLIST_FILE = GTMWebKitExample/Info.plist;
620 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
621 | PRODUCT_BUNDLE_IDENTIFIER = com.yang.GTMWebKitExample;
622 | PRODUCT_NAME = "$(TARGET_NAME)";
623 | SWIFT_VERSION = 4.2;
624 | TARGETED_DEVICE_FAMILY = 1;
625 | };
626 | name = Release;
627 | };
628 | /* End XCBuildConfiguration section */
629 |
630 | /* Begin XCConfigurationList section */
631 | 2657A3931FA9939300A717A3 /* Build configuration list for PBXProject "GTMWebKit" */ = {
632 | isa = XCConfigurationList;
633 | buildConfigurations = (
634 | 2657A39F1FA9939300A717A3 /* Debug */,
635 | 2657A3A01FA9939300A717A3 /* Release */,
636 | );
637 | defaultConfigurationIsVisible = 0;
638 | defaultConfigurationName = Release;
639 | };
640 | 2657A3A11FA9939300A717A3 /* Build configuration list for PBXNativeTarget "GTMWebKit" */ = {
641 | isa = XCConfigurationList;
642 | buildConfigurations = (
643 | 2657A3A21FA9939300A717A3 /* Debug */,
644 | 2657A3A31FA9939300A717A3 /* Release */,
645 | );
646 | defaultConfigurationIsVisible = 0;
647 | defaultConfigurationName = Release;
648 | };
649 | 2657A3C51FA993EA00A717A3 /* Build configuration list for PBXNativeTarget "GTMWebKitExample" */ = {
650 | isa = XCConfigurationList;
651 | buildConfigurations = (
652 | 2657A3C61FA993EA00A717A3 /* Debug */,
653 | 2657A3C71FA993EA00A717A3 /* Release */,
654 | );
655 | defaultConfigurationIsVisible = 0;
656 | defaultConfigurationName = Release;
657 | };
658 | /* End XCConfigurationList section */
659 | };
660 | rootObject = 2657A3901FA9939300A717A3 /* Project object */;
661 | }
662 |
--------------------------------------------------------------------------------