├── .gitignore ├── LICENSE.md ├── README.md └── source ├── GoogleAnalytics ├── GoogleAnalytics.swift └── GoogleAnalyticsHelper.swift ├── GoogleAnalyticsSwiftDemo ├── GoogleAnalyticsSwiftDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── GoogleAnalyticsSwiftDemo │ ├── AppDelegate.swift │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ └── MainMenu.xib │ ├── Info.plist │ ├── MainWindowController.swift │ └── MainWindowController.xib └── html └── gapp.html /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | 53 | Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/screenshots 64 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 atjason 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Note:** 2 | 3 | For Swift 5, Xcode 11.3 & Catalina Support and updated README, please check the 'swift5' branch. Thanks [revblaze](https://github.com/revblaze)'s conribution. 4 | 5 | Google Analytics for Mac OS X using Swift. 6 | 7 | 8 | # Introduction 9 | As we know, Google Analytics is perfect for user data collection and analytics. But unfortunately, there's no official SDK for Mac OS X. 10 | 11 | But still, there're several ways to use Google Analytics on Mac OS X. MacGoogleAnalytics may be what you found. 12 | 13 | Overall, there're 2 parts work together to use Google Analytics. 14 | 15 | - HTML File 16 | - This is the real place to send data to Google Analytics server. It uses Google Analytics's standard JavaScript API. 17 | 18 | - Mac OS X Part 19 | - In Mac OS X side, it loads the html file just mentioned. Send data like event to the html file as parameters. And then these data will be send in the html file through the JavaScript API. 20 | 21 | # HTML File 22 | You can find the html file in `source > html > gapp.html`. 23 | 24 | ## Parameter of HTML File 25 | The parameter of the html file is exactly the same with normal html file. 26 | 27 | ```html 28 | /gapp.html?param1=paramValue1¶m2=paramValue2&... 29 | ``` 30 | 31 | Demo of the html file with full parameters: 32 | 33 | ```html 34 | /gapp.html?id=UA-12345678-1&name=ihosts&version=1.1.0&ca=menu&ev=click&la=rate 35 | ``` 36 | 37 | Here are the supported parameter list. 38 | 39 | - `id` 40 | - The Google Analytics id, e.g., 'UA-12345678-1'. 41 | - **Note**: When you create a Google Analytics id, use the '**Mobile app**', but not 'Website'. 42 | 43 | ![1759091](http://p.appsites.io/2016-05-14-1759091.jpg) 44 | 45 | - `name` 46 | - The product name, e.g., 'ihosts' for [iHosts](http://ex.toolinbox.net/ga/url.html?utm_medium=ihosts&utm_source=GitHub&id=UA-26569268-10&url=https%3a%2f%2fitunes.apple.com%2fapp%2fid1102004240%3fls%3d1%26mt%3d12). You can track different products using same Google Analytics id, even I don't suggest you do that. 47 | - `version` 48 | - The app's version, e.g., '1.2.1'. 49 | - `ca` (*optional*) 50 | - The Google Analytics event category name. 51 | - `ev` (*optional*) 52 | - The Google Analytics event action name. 53 | - `la` (*optional*) 54 | - The Google Analytics event label value. 55 | 56 | **Note**: The full url include the parameters will be encoded. So no need to worry about the characters are valid or not. They will all be valid. 57 | 58 | ## Deploy the HTML File 59 | The html file should be deployed to a domain before it can be accessed. I deployed it at GitHub with my domain, you can feel free to use it. 60 | 61 | ```html 62 | http://atjason.com/MacGoogleAnalytics/gapp.html 63 | ``` 64 | 65 | You can also deploy it to your server with your domain. 66 | 67 | **Tip**: you may want to reduce the html file size by compressing the JavaScript code in it. Thus it will be faster to download. 68 | 69 | # Mac OS X Part 70 | There's only 2 files needed for Mac OS X part: `GoogleAnalytics.swift` and `GoogleAnalytics.swift`. 71 | 72 | ## GoogleAnalytics.swift 73 | Good news is, you even don't need to touch this file. 74 | 75 | This is the key file to integrate with Google Analytics. If you read the code, you will find it in fact loads the html file in a WebView, and combine the data as parameters for the html. 76 | 77 | ## GoogleAnalyticsHelper.swift 78 | This class help you easily use Google Analytics. 79 | 80 | Don't worry, you only need to update these properties: 81 | 82 | - `GAID` 83 | - The Google Analytics id, e.g., 'UA-12345678-1'. This is the 'id' used as parameter of html file. 84 | - `GAName` 85 | - The product name, e.g., 'ihosts' for **TODO iHosts Link**. This is the 'name' used as parameter of html file. 86 | - `PingURL` 87 | - The full url of gapp.html, e.g., 'http://atjason.com/MacGoogleAnalytics/gapp.html' mentioned above, or the url you deployed. 88 | - `PingTimeInterval` 89 | - By default it's 6h. It means telling Google Analytics every 6h that 'hey, I'm alive'. This will help Google Analytics to calculate the active users. 90 | 91 | # Demo Project Using Swift 92 | How to integrate MacGoogleAnalytics in your project? Just put the `GoogleAnalytics.swift` and `GoogleAnalyticsHelper.swift` in your project. 93 | 94 | Then, you need to start Google Analytics when app finished launching, stop it when app will terminate. 95 | 96 | ```swift 97 | func applicationDidFinishLaunching(aNotification: NSNotification) { 98 | GAHelper.startGoogleAnalytics() 99 | } 100 | 101 | func applicationWillTerminate(notification: NSNotification) { 102 | GAHelper.stopGoogleAnalytics() 103 | } 104 | ``` 105 | 106 | The main usage of Google Analytics is to send event. How to send the event? Just as simple as following code. 107 | 108 | ```swift 109 | GA.sendEvent("menu", event: "click", label: "rate") 110 | ``` 111 | 112 | That's all. 113 | 114 | ## Work With HTTP 115 | When run your project with MacGoogleAnalytics, you may meet this error: 116 | 117 | *App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.* 118 | 119 | Apple disable http access by default for security reason. If you really need to use http, could manually allow it. Open `Info.plist`, and add the following lines: 120 | 121 | ```swift 122 | NSAppTransportSecurity 123 | 124 | NSAllowsArbitraryLoads 125 | 126 | 127 | ``` 128 | 129 | Please keep in mind that this solution should be your last resort. You’d ideally want to enable HTTPS on your service, or next, whitelist domains on which you want HTTP and if none of this is possible, then use this approach. 130 | 131 | # Demo Project Using Objective C 132 | TODO 133 | 134 | # View Data in Google Analytics Site 135 | After data are collected, you can view them in Google Analytics as normal: [https://analytics.google.com/analytics/web/](https://analytics.google.com/analytics/web/). During debug, you can also check whether it works or not in 'Real-Time'. 136 | 137 | Just give a tip for OS X version. In the demo app using swift, it collect event of `options > option_a > yes or no`. You may want to know, how many users enable this option in OS X 10.10 and how many for 10.11. How to do it? 138 | 139 | Open the `Behavior > Events > Top Events`, select `options > option_a`. Here you should be able to see all the events. Then add a new custom Segment, in `Technology > Operating System Version`, add *contains* '10.10', save it as 'OS X 10.10'. Add another Segment for 'OS X 10.11'. 140 | 141 | ![1747211](http://p.appsites.io/2016-05-14-1747211.jpg) 142 | 143 | And then, apply the Segments, it could distinguish the data of OS X 10.10 or 10.11. 144 | 145 | ![1750021](http://p.appsites.io/2016-05-14-1750021.jpg) 146 | 147 | # Release on Mac App Store 148 | Yes, this way could be released on Mac App Store. In fact, these of my apps have already released on Mac App Store. 149 | 150 | - [iHosts](http://ex.toolinbox.net/ga/url.html?utm_medium=ihosts&utm_source=GitHub&id=UA-26569268-10&url=https%3a%2f%2fitunes.apple.com%2fapp%2fid1102004240%3fls%3d1%26mt%3d12) 151 | - [Daily Clipboard](http://ex.toolinbox.net/ga/url.html?utm_medium=clip&utm_source=GitHub&id=UA-26569268-10&url=https%3a%2f%2fitunes.apple.com%2fapp%2fid1056935452%3fls%3d1%26mt%3d12) 152 | - [Attention Timer](http://ex.toolinbox.net/ga/url.html?utm_medium=timer&utm_source=GitHub&id=UA-26569268-10&url=https%3a%2f%2fitunes.apple.com%2fapp%2fid1062139745%3fls%3d1%26mt%3d12) 153 | 154 | ## Show Your Product 155 | If your product using MacGoogleAnalytics and you'd like to share it here, pull requests welcome :) 156 | 157 | # License 158 | MacGoogleAnalytics is licensed under the terms of the MIT license. Just feel free to use it :) 159 | 160 | # Donate 161 | If you think Mac Google Analytics is helpful for you, welcome to [donate](https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=quietjason%40gmail%2ecom&lc=US&item_name=Mac%20Google%20Analytics&button_subtype=services¤cy_code=USD&bn=PP%2dBuyNowBF%3abtn_buynow_SM%2egif%3aNonHosted) :) 162 | 163 | 164 | -------------------------------------------------------------------------------- /source/GoogleAnalytics/GoogleAnalytics.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GoogleAnalytics.swift 3 | // Test 4 | // 5 | // Created by Jason Zheng on 11/27/15. 6 | // Copyright © 2015 Jason Zheng. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import WebKit 11 | 12 | let GA = GoogleAnalytics.sharedInstance 13 | 14 | class GoogleAnalytics: NSObject { 15 | 16 | static let sharedInstance = GoogleAnalytics() 17 | private override init() { super.init() } 18 | 19 | private var webViews = Set() 20 | private let timeIntervalDelayToRemoveWebView = NSTimeInterval(10) 21 | private weak var timer: NSTimer? 22 | 23 | var yes = "yes" 24 | var no = "no" 25 | var none = "none" 26 | 27 | private var pingURL = "" 28 | private let userUUIDKey = "User UUID" 29 | private let paramCategory = "ca" 30 | private let paramEvent = "ev" 31 | private let paramLabel = "la" 32 | 33 | func setPingURL(url: String) { 34 | pingURL = url 35 | } 36 | 37 | func startPing(timeInternal: NSTimeInterval) { 38 | if timer == nil { 39 | timer = NSTimer.scheduledTimerWithTimeInterval( 40 | timeInternal, target: self, selector: #selector(GoogleAnalytics.doPing), 41 | userInfo: nil, repeats: true) 42 | timer?.tolerance = timeInternal * 0.1 43 | } 44 | 45 | timer?.fire() 46 | } 47 | 48 | func stopPing() { 49 | timer?.invalidate() 50 | } 51 | 52 | func doPing() { 53 | GA.sendEvent("app", event: "ping", label: GAHelper.getAppVersion()) 54 | } 55 | 56 | func doPingURL(url: String) { 57 | 58 | let encodedURL = url.stringByAddingPercentEncodingWithAllowedCharacters( 59 | NSCharacterSet.URLQueryAllowedCharacterSet()) 60 | 61 | if encodedURL != nil { 62 | if let requestURL = NSURL(string: encodedURL!) { 63 | dispatch_async(dispatch_get_main_queue(), { 64 | let newWebView = WebView() 65 | self.webViews.insert(newWebView) 66 | newWebView.frameLoadDelegate = self 67 | 68 | let request = NSURLRequest(URL: requestURL) 69 | newWebView.mainFrame.loadRequest(request) 70 | }) 71 | 72 | } else { 73 | NSLog("Failed to generate NSURL from \(url)") 74 | } 75 | 76 | } else { 77 | NSLog("Failed to encode URL from \(url)") 78 | } 79 | } 80 | 81 | func sendEvent(category: String, event: String?, label: String?) { 82 | var url = pingURL 83 | 84 | if !category.isEmpty { 85 | if !url.containsString("?") { 86 | url += "?" 87 | } else { 88 | url += "&" 89 | } 90 | 91 | url += "\(paramCategory)=\(category)" 92 | 93 | if (event != nil) && (!event!.isEmpty) { 94 | url += "&\(paramEvent)=\(event!)" 95 | 96 | if (label != nil) && (!label!.isEmpty) { 97 | url += "&\(paramLabel)=\(label!)" 98 | } 99 | } 100 | } 101 | 102 | self.performSelector(#selector(GoogleAnalytics.doPingURL(_:)), withObject: url) 103 | } 104 | 105 | func initUUIDIfNeeded() { 106 | let userDefaults = NSUserDefaults.standardUserDefaults() 107 | 108 | let userUUID = userDefaults.valueForKey(userUUIDKey) as? String 109 | 110 | if userUUID == nil { 111 | userDefaults.setValue(NSUUID().UUIDString, forKey: userUUIDKey) 112 | 113 | let locale = NSLocale.currentLocale().objectForKey(NSLocaleIdentifier) as? String ?? "" 114 | let os = GAHelper.getOSXVersion() 115 | let version = GAHelper.getAppVersion() 116 | let info = "\(locale)_\(os)_\(version)" 117 | GA.sendEvent("app", event: "init", label: info) 118 | } 119 | } 120 | } 121 | 122 | extension GoogleAnalytics: WebFrameLoadDelegate { 123 | 124 | func webView(sender: WebView!, didFinishLoadForFrame frame: WebFrame!) { 125 | self.performSelector(#selector(GoogleAnalytics.removeUnusedWebView(_:)), 126 | withObject: sender, 127 | afterDelay: timeIntervalDelayToRemoveWebView) 128 | } 129 | 130 | func removeUnusedWebView(webView: WebView) { 131 | webView.close() 132 | self.webViews.remove(webView) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /source/GoogleAnalytics/GoogleAnalyticsHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GoogleAnalytics.swift 3 | // Test 4 | // 5 | // Created by Jason Zheng on 11/27/15. 6 | // Copyright © 2015 Jason Zheng. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | typealias GAHelper = GoogleAnalyticsHelper 12 | 13 | class GoogleAnalyticsHelper { 14 | 15 | static let GAID = "UA-76794534-4" 16 | static let GAName = "Demo" 17 | static let PingURL = "http://atjason.com/MacGoogleAnalytics/gapp.html?id=\(GAID)&name=\(GAName)&version=\(GoogleAnalyticsHelper.getAppVersion())" 18 | static let PingTimeInterval: NSTimeInterval = 3600 * 6 // Ping every 6h 19 | 20 | // MARK: - Helper 21 | 22 | static func startGoogleAnalytics() { 23 | GA.setPingURL(PingURL) 24 | 25 | GA.startPing(PingTimeInterval) 26 | GA.sendEvent("app", event: "start", label: getAppVersion()) 27 | GA.initUUIDIfNeeded() 28 | } 29 | 30 | static func stopGoogleAnalytics() { 31 | GA.stopPing() 32 | } 33 | 34 | static func getAppVersion() -> String { 35 | let versionObject = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] 36 | let version = versionObject as? String ?? "0.0.0" 37 | 38 | return version 39 | } 40 | 41 | static func getOSXVersion() -> String { 42 | let version = NSProcessInfo.processInfo().operatingSystemVersion 43 | let versionString = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)" 44 | return versionString 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /source/GoogleAnalyticsSwiftDemo/GoogleAnalyticsSwiftDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 96806FA91CE5BA930012CF72 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96806FA81CE5BA930012CF72 /* AppDelegate.swift */; }; 11 | 96806FAB1CE5BA930012CF72 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 96806FAA1CE5BA930012CF72 /* Assets.xcassets */; }; 12 | 96806FAE1CE5BA930012CF72 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 96806FAC1CE5BA930012CF72 /* MainMenu.xib */; }; 13 | 96806FB71CE5BABD0012CF72 /* MainWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96806FB51CE5BABD0012CF72 /* MainWindowController.swift */; }; 14 | 96806FB81CE5BABD0012CF72 /* MainWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 96806FB61CE5BABD0012CF72 /* MainWindowController.xib */; }; 15 | 96806FBB1CE5BB7D0012CF72 /* GoogleAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96806FBA1CE5BB7D0012CF72 /* GoogleAnalytics.swift */; }; 16 | 96806FBD1CE5BE930012CF72 /* GoogleAnalyticsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96806FBC1CE5BE930012CF72 /* GoogleAnalyticsHelper.swift */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | 96806FA51CE5BA930012CF72 /* GoogleAnalyticsSwiftDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GoogleAnalyticsSwiftDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | 96806FA81CE5BA930012CF72 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 22 | 96806FAA1CE5BA930012CF72 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 23 | 96806FAD1CE5BA930012CF72 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 24 | 96806FAF1CE5BA930012CF72 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 25 | 96806FB51CE5BABD0012CF72 /* MainWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainWindowController.swift; sourceTree = ""; }; 26 | 96806FB61CE5BABD0012CF72 /* MainWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainWindowController.xib; sourceTree = ""; }; 27 | 96806FBA1CE5BB7D0012CF72 /* GoogleAnalytics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GoogleAnalytics.swift; path = ../../GoogleAnalytics/GoogleAnalytics.swift; sourceTree = ""; }; 28 | 96806FBC1CE5BE930012CF72 /* GoogleAnalyticsHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GoogleAnalyticsHelper.swift; path = ../../GoogleAnalytics/GoogleAnalyticsHelper.swift; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 96806FA21CE5BA930012CF72 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 96806F9C1CE5BA930012CF72 = { 43 | isa = PBXGroup; 44 | children = ( 45 | 96806FA71CE5BA930012CF72 /* GoogleAnalyticsSwiftDemo */, 46 | 96806FA61CE5BA930012CF72 /* Products */, 47 | ); 48 | sourceTree = ""; 49 | }; 50 | 96806FA61CE5BA930012CF72 /* Products */ = { 51 | isa = PBXGroup; 52 | children = ( 53 | 96806FA51CE5BA930012CF72 /* GoogleAnalyticsSwiftDemo.app */, 54 | ); 55 | name = Products; 56 | sourceTree = ""; 57 | }; 58 | 96806FA71CE5BA930012CF72 /* GoogleAnalyticsSwiftDemo */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 96806FB91CE5BB6B0012CF72 /* GoogleAnalytics */, 62 | 96806FA81CE5BA930012CF72 /* AppDelegate.swift */, 63 | 96806FB51CE5BABD0012CF72 /* MainWindowController.swift */, 64 | 96806FB61CE5BABD0012CF72 /* MainWindowController.xib */, 65 | 96806FAA1CE5BA930012CF72 /* Assets.xcassets */, 66 | 96806FAC1CE5BA930012CF72 /* MainMenu.xib */, 67 | 96806FAF1CE5BA930012CF72 /* Info.plist */, 68 | ); 69 | path = GoogleAnalyticsSwiftDemo; 70 | sourceTree = ""; 71 | }; 72 | 96806FB91CE5BB6B0012CF72 /* GoogleAnalytics */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 96806FBA1CE5BB7D0012CF72 /* GoogleAnalytics.swift */, 76 | 96806FBC1CE5BE930012CF72 /* GoogleAnalyticsHelper.swift */, 77 | ); 78 | name = GoogleAnalytics; 79 | sourceTree = ""; 80 | }; 81 | /* End PBXGroup section */ 82 | 83 | /* Begin PBXNativeTarget section */ 84 | 96806FA41CE5BA930012CF72 /* GoogleAnalyticsSwiftDemo */ = { 85 | isa = PBXNativeTarget; 86 | buildConfigurationList = 96806FB21CE5BA930012CF72 /* Build configuration list for PBXNativeTarget "GoogleAnalyticsSwiftDemo" */; 87 | buildPhases = ( 88 | 96806FA11CE5BA930012CF72 /* Sources */, 89 | 96806FA21CE5BA930012CF72 /* Frameworks */, 90 | 96806FA31CE5BA930012CF72 /* Resources */, 91 | ); 92 | buildRules = ( 93 | ); 94 | dependencies = ( 95 | ); 96 | name = GoogleAnalyticsSwiftDemo; 97 | productName = GoogleAnalyticsSwiftDemo; 98 | productReference = 96806FA51CE5BA930012CF72 /* GoogleAnalyticsSwiftDemo.app */; 99 | productType = "com.apple.product-type.application"; 100 | }; 101 | /* End PBXNativeTarget section */ 102 | 103 | /* Begin PBXProject section */ 104 | 96806F9D1CE5BA930012CF72 /* Project object */ = { 105 | isa = PBXProject; 106 | attributes = { 107 | LastSwiftUpdateCheck = 0730; 108 | LastUpgradeCheck = 0730; 109 | ORGANIZATIONNAME = "Jason Zheng"; 110 | TargetAttributes = { 111 | 96806FA41CE5BA930012CF72 = { 112 | CreatedOnToolsVersion = 7.3; 113 | }; 114 | }; 115 | }; 116 | buildConfigurationList = 96806FA01CE5BA930012CF72 /* Build configuration list for PBXProject "GoogleAnalyticsSwiftDemo" */; 117 | compatibilityVersion = "Xcode 3.2"; 118 | developmentRegion = English; 119 | hasScannedForEncodings = 0; 120 | knownRegions = ( 121 | en, 122 | Base, 123 | ); 124 | mainGroup = 96806F9C1CE5BA930012CF72; 125 | productRefGroup = 96806FA61CE5BA930012CF72 /* Products */; 126 | projectDirPath = ""; 127 | projectRoot = ""; 128 | targets = ( 129 | 96806FA41CE5BA930012CF72 /* GoogleAnalyticsSwiftDemo */, 130 | ); 131 | }; 132 | /* End PBXProject section */ 133 | 134 | /* Begin PBXResourcesBuildPhase section */ 135 | 96806FA31CE5BA930012CF72 /* Resources */ = { 136 | isa = PBXResourcesBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | 96806FAB1CE5BA930012CF72 /* Assets.xcassets in Resources */, 140 | 96806FB81CE5BABD0012CF72 /* MainWindowController.xib in Resources */, 141 | 96806FAE1CE5BA930012CF72 /* MainMenu.xib in Resources */, 142 | ); 143 | runOnlyForDeploymentPostprocessing = 0; 144 | }; 145 | /* End PBXResourcesBuildPhase section */ 146 | 147 | /* Begin PBXSourcesBuildPhase section */ 148 | 96806FA11CE5BA930012CF72 /* Sources */ = { 149 | isa = PBXSourcesBuildPhase; 150 | buildActionMask = 2147483647; 151 | files = ( 152 | 96806FB71CE5BABD0012CF72 /* MainWindowController.swift in Sources */, 153 | 96806FA91CE5BA930012CF72 /* AppDelegate.swift in Sources */, 154 | 96806FBB1CE5BB7D0012CF72 /* GoogleAnalytics.swift in Sources */, 155 | 96806FBD1CE5BE930012CF72 /* GoogleAnalyticsHelper.swift in Sources */, 156 | ); 157 | runOnlyForDeploymentPostprocessing = 0; 158 | }; 159 | /* End PBXSourcesBuildPhase section */ 160 | 161 | /* Begin PBXVariantGroup section */ 162 | 96806FAC1CE5BA930012CF72 /* MainMenu.xib */ = { 163 | isa = PBXVariantGroup; 164 | children = ( 165 | 96806FAD1CE5BA930012CF72 /* Base */, 166 | ); 167 | name = MainMenu.xib; 168 | sourceTree = ""; 169 | }; 170 | /* End PBXVariantGroup section */ 171 | 172 | /* Begin XCBuildConfiguration section */ 173 | 96806FB01CE5BA930012CF72 /* Debug */ = { 174 | isa = XCBuildConfiguration; 175 | buildSettings = { 176 | ALWAYS_SEARCH_USER_PATHS = NO; 177 | CLANG_ANALYZER_NONNULL = YES; 178 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 179 | CLANG_CXX_LIBRARY = "libc++"; 180 | CLANG_ENABLE_MODULES = YES; 181 | CLANG_ENABLE_OBJC_ARC = YES; 182 | CLANG_WARN_BOOL_CONVERSION = YES; 183 | CLANG_WARN_CONSTANT_CONVERSION = YES; 184 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 185 | CLANG_WARN_EMPTY_BODY = YES; 186 | CLANG_WARN_ENUM_CONVERSION = YES; 187 | CLANG_WARN_INT_CONVERSION = YES; 188 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 189 | CLANG_WARN_UNREACHABLE_CODE = YES; 190 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 191 | CODE_SIGN_IDENTITY = "-"; 192 | COPY_PHASE_STRIP = NO; 193 | DEBUG_INFORMATION_FORMAT = dwarf; 194 | ENABLE_STRICT_OBJC_MSGSEND = YES; 195 | ENABLE_TESTABILITY = YES; 196 | GCC_C_LANGUAGE_STANDARD = gnu99; 197 | GCC_DYNAMIC_NO_PIC = NO; 198 | GCC_NO_COMMON_BLOCKS = YES; 199 | GCC_OPTIMIZATION_LEVEL = 0; 200 | GCC_PREPROCESSOR_DEFINITIONS = ( 201 | "DEBUG=1", 202 | "$(inherited)", 203 | ); 204 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 205 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 206 | GCC_WARN_UNDECLARED_SELECTOR = YES; 207 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 208 | GCC_WARN_UNUSED_FUNCTION = YES; 209 | GCC_WARN_UNUSED_VARIABLE = YES; 210 | MACOSX_DEPLOYMENT_TARGET = 10.10; 211 | MTL_ENABLE_DEBUG_INFO = YES; 212 | ONLY_ACTIVE_ARCH = YES; 213 | SDKROOT = macosx; 214 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 215 | }; 216 | name = Debug; 217 | }; 218 | 96806FB11CE5BA930012CF72 /* Release */ = { 219 | isa = XCBuildConfiguration; 220 | buildSettings = { 221 | ALWAYS_SEARCH_USER_PATHS = NO; 222 | CLANG_ANALYZER_NONNULL = YES; 223 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 224 | CLANG_CXX_LIBRARY = "libc++"; 225 | CLANG_ENABLE_MODULES = YES; 226 | CLANG_ENABLE_OBJC_ARC = YES; 227 | CLANG_WARN_BOOL_CONVERSION = YES; 228 | CLANG_WARN_CONSTANT_CONVERSION = YES; 229 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 230 | CLANG_WARN_EMPTY_BODY = YES; 231 | CLANG_WARN_ENUM_CONVERSION = YES; 232 | CLANG_WARN_INT_CONVERSION = YES; 233 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 234 | CLANG_WARN_UNREACHABLE_CODE = YES; 235 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 236 | CODE_SIGN_IDENTITY = "-"; 237 | COPY_PHASE_STRIP = NO; 238 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 239 | ENABLE_NS_ASSERTIONS = NO; 240 | ENABLE_STRICT_OBJC_MSGSEND = YES; 241 | GCC_C_LANGUAGE_STANDARD = gnu99; 242 | GCC_NO_COMMON_BLOCKS = YES; 243 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 244 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 245 | GCC_WARN_UNDECLARED_SELECTOR = YES; 246 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 247 | GCC_WARN_UNUSED_FUNCTION = YES; 248 | GCC_WARN_UNUSED_VARIABLE = YES; 249 | MACOSX_DEPLOYMENT_TARGET = 10.10; 250 | MTL_ENABLE_DEBUG_INFO = NO; 251 | SDKROOT = macosx; 252 | }; 253 | name = Release; 254 | }; 255 | 96806FB31CE5BA930012CF72 /* Debug */ = { 256 | isa = XCBuildConfiguration; 257 | buildSettings = { 258 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 259 | COMBINE_HIDPI_IMAGES = YES; 260 | INFOPLIST_FILE = GoogleAnalyticsSwiftDemo/Info.plist; 261 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 262 | PRODUCT_BUNDLE_IDENTIFIER = com.atjason.MacGoogleAnalytics.GoogleAnalyticsSwiftDemo; 263 | PRODUCT_NAME = "$(TARGET_NAME)"; 264 | }; 265 | name = Debug; 266 | }; 267 | 96806FB41CE5BA930012CF72 /* Release */ = { 268 | isa = XCBuildConfiguration; 269 | buildSettings = { 270 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 271 | COMBINE_HIDPI_IMAGES = YES; 272 | INFOPLIST_FILE = GoogleAnalyticsSwiftDemo/Info.plist; 273 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 274 | PRODUCT_BUNDLE_IDENTIFIER = com.atjason.MacGoogleAnalytics.GoogleAnalyticsSwiftDemo; 275 | PRODUCT_NAME = "$(TARGET_NAME)"; 276 | }; 277 | name = Release; 278 | }; 279 | /* End XCBuildConfiguration section */ 280 | 281 | /* Begin XCConfigurationList section */ 282 | 96806FA01CE5BA930012CF72 /* Build configuration list for PBXProject "GoogleAnalyticsSwiftDemo" */ = { 283 | isa = XCConfigurationList; 284 | buildConfigurations = ( 285 | 96806FB01CE5BA930012CF72 /* Debug */, 286 | 96806FB11CE5BA930012CF72 /* Release */, 287 | ); 288 | defaultConfigurationIsVisible = 0; 289 | defaultConfigurationName = Release; 290 | }; 291 | 96806FB21CE5BA930012CF72 /* Build configuration list for PBXNativeTarget "GoogleAnalyticsSwiftDemo" */ = { 292 | isa = XCConfigurationList; 293 | buildConfigurations = ( 294 | 96806FB31CE5BA930012CF72 /* Debug */, 295 | 96806FB41CE5BA930012CF72 /* Release */, 296 | ); 297 | defaultConfigurationIsVisible = 0; 298 | defaultConfigurationName = Release; 299 | }; 300 | /* End XCConfigurationList section */ 301 | }; 302 | rootObject = 96806F9D1CE5BA930012CF72 /* Project object */; 303 | } 304 | -------------------------------------------------------------------------------- /source/GoogleAnalyticsSwiftDemo/GoogleAnalyticsSwiftDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /source/GoogleAnalyticsSwiftDemo/GoogleAnalyticsSwiftDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // GoogleAnalyticsSwiftDemo 4 | // 5 | // Created by Jason Zheng on 5/13/16. 6 | // Copyright © 2016 Jason Zheng. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | var mainWindowController: MainWindowController? 15 | 16 | func applicationDidFinishLaunching(aNotification: NSNotification) { 17 | let mainWindowController = MainWindowController() 18 | mainWindowController.showWindow(self) 19 | 20 | self.mainWindowController = mainWindowController 21 | 22 | GAHelper.startGoogleAnalytics() 23 | } 24 | 25 | func applicationWillTerminate(notification: NSNotification) { 26 | GAHelper.stopGoogleAnalytics() 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /source/GoogleAnalyticsSwiftDemo/GoogleAnalyticsSwiftDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /source/GoogleAnalyticsSwiftDemo/GoogleAnalyticsSwiftDemo/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 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 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | Default 536 | 537 | 538 | 539 | 540 | 541 | 542 | Left to Right 543 | 544 | 545 | 546 | 547 | 548 | 549 | Right to Left 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | Default 561 | 562 | 563 | 564 | 565 | 566 | 567 | Left to Right 568 | 569 | 570 | 571 | 572 | 573 | 574 | Right to Left 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | -------------------------------------------------------------------------------- /source/GoogleAnalyticsSwiftDemo/GoogleAnalyticsSwiftDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 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 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2016 Jason Zheng. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | NSAppTransportSecurity 34 | 35 | NSAllowsArbitraryLoads 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /source/GoogleAnalyticsSwiftDemo/GoogleAnalyticsSwiftDemo/MainWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainWindowController.swift 3 | // GoogleAnalyticsSwiftDemo 4 | // 5 | // Created by Jason Zheng on 5/13/16. 6 | // Copyright © 2016 Jason Zheng. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class MainWindowController: NSWindowController { 12 | 13 | @IBOutlet weak var optionA: NSButton! 14 | 15 | override var windowNibName: String? { 16 | return "MainWindowController" 17 | } 18 | 19 | @IBAction func sendEvent(sender: NSButton!) { 20 | let selected = (optionA.state == NSOnState) 21 | let label = selected ? GA.yes : GA.no 22 | GA.sendEvent("options", event: "option_a", label: label) 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /source/GoogleAnalyticsSwiftDemo/GoogleAnalyticsSwiftDemo/MainWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 32 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /source/html/gapp.html: -------------------------------------------------------------------------------- 1 | 54 | 55 | 56 | --------------------------------------------------------------------------------