mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-11 10:25:57 +02:00
Merge pull request #1913 from vector-im/e2e_telemetry
Refresh Analytics code
This commit is contained in:
+4
-2
@@ -4,8 +4,10 @@ Changes in 0.6.18 ()
|
||||
Improvements:
|
||||
* Upgrade MatrixKit version ().
|
||||
* RoomVC: Add a re-request keys button on message unable to decrypt (#1879).
|
||||
* Analytics: Move code from AppDelegate to a dedicated class: Analytics.
|
||||
* Analytics: Track Matrix SDK stats (time to startup the app).
|
||||
* Added the i18n localisation strings to the accessibility labels (#1842), thanks to @einMarco (PR#1906).
|
||||
|
||||
|
||||
Bug fix:
|
||||
* RoomVC: Read receipts processing dramatically slows down UI (#1899).
|
||||
|
||||
@@ -1127,4 +1129,4 @@ Changes in Vector iOS in 0.1.0 (2016-01-29)
|
||||
Changes in Vector iOS in 0.0.1 (2015-11-16)
|
||||
===============================================
|
||||
|
||||
* Creation : The first implementation of Vector application based on Matrix iOS Kit v0.2.7.
|
||||
* Creation : The first implementation of Vector application based on Matrix iOS Kit v0.2.7.
|
||||
|
||||
@@ -59,6 +59,11 @@
|
||||
32471CE11F13AC1500BDF50A /* RoomMembershipExpandedWithPaginationTitleBubbleCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 32471CDF1F13AC1500BDF50A /* RoomMembershipExpandedWithPaginationTitleBubbleCell.m */; };
|
||||
32471CE21F13AC1500BDF50A /* RoomMembershipExpandedWithPaginationTitleBubbleCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32471CE01F13AC1500BDF50A /* RoomMembershipExpandedWithPaginationTitleBubbleCell.xib */; };
|
||||
325E1C151E8D03950018D91E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 325E1C131E8D03950018D91E /* LaunchScreen.storyboard */; };
|
||||
3267EFB220E2A04100FF1CAA /* Analytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3267EFB120E2A04100FF1CAA /* Analytics.m */; };
|
||||
3267EFB720E379FE00FF1CAA /* CHANGES.rst in Resources */ = {isa = PBXBuildFile; fileRef = 3267EFB320E379FD00FF1CAA /* CHANGES.rst */; };
|
||||
3267EFB820E379FE00FF1CAA /* Podfile in Resources */ = {isa = PBXBuildFile; fileRef = 3267EFB420E379FD00FF1CAA /* Podfile */; };
|
||||
3267EFB920E379FE00FF1CAA /* AUTHORS.rst in Resources */ = {isa = PBXBuildFile; fileRef = 3267EFB520E379FD00FF1CAA /* AUTHORS.rst */; };
|
||||
3267EFBA20E379FE00FF1CAA /* README.rst in Resources */ = {isa = PBXBuildFile; fileRef = 3267EFB620E379FD00FF1CAA /* README.rst */; };
|
||||
327382B51F276AD200356143 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382A81F276AD200356143 /* InfoPlist.strings */; };
|
||||
327382B61F276AD200356143 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382AA1F276AD200356143 /* Localizable.strings */; };
|
||||
327382B71F276AD200356143 /* Vector.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382AC1F276AD200356143 /* Vector.strings */; };
|
||||
@@ -725,6 +730,12 @@
|
||||
32471CDF1F13AC1500BDF50A /* RoomMembershipExpandedWithPaginationTitleBubbleCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMembershipExpandedWithPaginationTitleBubbleCell.m; sourceTree = "<group>"; };
|
||||
32471CE01F13AC1500BDF50A /* RoomMembershipExpandedWithPaginationTitleBubbleCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RoomMembershipExpandedWithPaginationTitleBubbleCell.xib; sourceTree = "<group>"; };
|
||||
325E1C141E8D03950018D91E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
3267EFB020E2A04100FF1CAA /* Analytics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Analytics.h; path = Riot/Analytics/Analytics.h; sourceTree = SOURCE_ROOT; };
|
||||
3267EFB120E2A04100FF1CAA /* Analytics.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Analytics.m; path = Riot/Analytics/Analytics.m; sourceTree = SOURCE_ROOT; };
|
||||
3267EFB320E379FD00FF1CAA /* CHANGES.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CHANGES.rst; sourceTree = "<group>"; };
|
||||
3267EFB420E379FD00FF1CAA /* Podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Podfile; sourceTree = "<group>"; };
|
||||
3267EFB520E379FD00FF1CAA /* AUTHORS.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AUTHORS.rst; sourceTree = "<group>"; };
|
||||
3267EFB620E379FD00FF1CAA /* README.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.rst; sourceTree = "<group>"; };
|
||||
327382A91F276AD200356143 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = InfoPlist.strings; sourceTree = "<group>"; };
|
||||
327382AB1F276AD200356143 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
327382AD1F276AD200356143 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Vector.strings; sourceTree = "<group>"; };
|
||||
@@ -1597,6 +1608,16 @@
|
||||
path = "jitsi-meet";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3267EFAF20E2A00F00FF1CAA /* Analytics */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3267EFB020E2A04100FF1CAA /* Analytics.h */,
|
||||
3267EFB120E2A04100FF1CAA /* Analytics.m */,
|
||||
);
|
||||
name = Analytics;
|
||||
path = "New Group";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
327382A71F276AD200356143 /* de.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -1796,6 +1817,7 @@
|
||||
F083BB081E7009EC00A9B29C /* Riot */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3267EFAF20E2A00F00FF1CAA /* Analytics */,
|
||||
F083BB091E7009EC00A9B29C /* API */,
|
||||
F083BB0E1E7009EC00A9B29C /* Assets */,
|
||||
F083BBE41E7009EC00A9B29C /* Categories */,
|
||||
@@ -2682,6 +2704,10 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F083BB081E7009EC00A9B29C /* Riot */,
|
||||
3267EFB520E379FD00FF1CAA /* AUTHORS.rst */,
|
||||
3267EFB320E379FD00FF1CAA /* CHANGES.rst */,
|
||||
3267EFB420E379FD00FF1CAA /* Podfile */,
|
||||
3267EFB620E379FD00FF1CAA /* README.rst */,
|
||||
F083BB021E7005FD00A9B29C /* RiotTests */,
|
||||
24CBEC4F1F0EAD310093EABB /* RiotShareExtension */,
|
||||
92726A441F58737A004AD26F /* SiriIntents */,
|
||||
@@ -2988,6 +3014,7 @@
|
||||
F083BD641E7009ED00A9B29C /* direct_icon@3x.png in Resources */,
|
||||
F083BE261E7009ED00A9B29C /* SegmentedViewController.xib in Resources */,
|
||||
F083BE161E7009ED00A9B29C /* MediaAlbumContentViewController.xib in Resources */,
|
||||
3267EFB720E379FE00FF1CAA /* CHANGES.rst in Resources */,
|
||||
F083BD441E7009ED00A9B29C /* call_speaker_on_icon@3x.png in Resources */,
|
||||
F0614A0F1EDDCCE700F5DC9A /* jump_to_unread@3x.png in Resources */,
|
||||
F083BE511E7009ED00A9B29C /* RoomOutgoingEncryptedTextMsgBubbleCell.xib in Resources */,
|
||||
@@ -3040,6 +3067,7 @@
|
||||
32BB89F0204D86DA002F3AEC /* InfoPlist.strings in Resources */,
|
||||
F083BD3E1E7009ED00A9B29C /* call_hangup_icon@3x.png in Resources */,
|
||||
32AE61F21F0D2183007255F4 /* InfoPlist.strings in Resources */,
|
||||
3267EFB920E379FE00FF1CAA /* AUTHORS.rst in Resources */,
|
||||
F083BDB91E7009ED00A9B29C /* remove_icon_pink.png in Resources */,
|
||||
F083BE531E7009ED00A9B29C /* RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.xib in Resources */,
|
||||
F083BD7F1E7009ED00A9B29C /* error@3x.png in Resources */,
|
||||
@@ -3070,6 +3098,7 @@
|
||||
F083BD5F1E7009ED00A9B29C /* details_icon.png in Resources */,
|
||||
F083BE241E7009ED00A9B29C /* RoomViewController.xib in Resources */,
|
||||
F083BE7B1E7009ED00A9B29C /* RoomInputToolbarView.xib in Resources */,
|
||||
3267EFB820E379FE00FF1CAA /* Podfile in Resources */,
|
||||
F0E05A3D1EA0F9EB004B83FB /* tab_people_selected@2x.png in Resources */,
|
||||
F0E05A451EA0F9EB004B83FB /* tab_rooms.png in Resources */,
|
||||
F083BE751E7009ED00A9B29C /* RoomOutgoingTextMsgWithoutSenderNameBubbleCell.xib in Resources */,
|
||||
@@ -3319,6 +3348,7 @@
|
||||
F0E05A3C1EA0F9EB004B83FB /* tab_people_selected.png in Resources */,
|
||||
F083BD221E7009ED00A9B29C /* add_participant.png in Resources */,
|
||||
F083BDC61E7009ED00A9B29C /* search_bg@2x.png in Resources */,
|
||||
3267EFBA20E379FE00FF1CAA /* README.rst in Resources */,
|
||||
F083BD421E7009ED00A9B29C /* call_speaker_on_icon.png in Resources */,
|
||||
F04AF26D1F83A4C100D20F4D /* Localizable.strings in Resources */,
|
||||
F083BD9A1E7009ED00A9B29C /* logo@3x.png in Resources */,
|
||||
@@ -3543,6 +3573,7 @@
|
||||
321082B21F0E9F40002E0091 /* RoomMembershipCollapsedBubbleCell.m in Sources */,
|
||||
32C2356F1F7B871800E38FC5 /* WidgetPickerViewController.m in Sources */,
|
||||
F083BE661E7009ED00A9B29C /* RoomIncomingTextMsgWithPaginationTitleBubbleCell.m in Sources */,
|
||||
3267EFB220E2A04100FF1CAA /* Analytics.m in Sources */,
|
||||
F083BE141E7009ED00A9B29C /* HomeViewController.m in Sources */,
|
||||
F083BDFB1E7009ED00A9B29C /* RoomSearchDataSource.m in Sources */,
|
||||
32EF474920B6EE990031695C /* StickerPickerViewController.m in Sources */,
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright 2018 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <MatrixSDK/MatrixSDK.h>
|
||||
|
||||
/**
|
||||
`Analytics` sends analytics to an analytics tool.
|
||||
*/
|
||||
@interface Analytics : NSObject <MXAnalyticsDelegate>
|
||||
|
||||
/**
|
||||
Returns the shared Analytics manager.
|
||||
|
||||
@return the shared Analytics manager.
|
||||
*/
|
||||
+ (instancetype)sharedInstance;
|
||||
|
||||
/**
|
||||
Start doing analytics if the settings `enableCrashReport` is enabled.
|
||||
*/
|
||||
- (void)start;
|
||||
|
||||
/**
|
||||
Stop doing analytics.
|
||||
*/
|
||||
- (void)stop;
|
||||
|
||||
/**
|
||||
Track a screen display.
|
||||
|
||||
@param screenName the name of the displayed screen.
|
||||
*/
|
||||
- (void)trackScreen:(NSString*)screenName;
|
||||
|
||||
/**
|
||||
Flush analytics data.
|
||||
*/
|
||||
- (void)dispatch;
|
||||
|
||||
/**
|
||||
Track how long the launch screen has been displayed to the end user.
|
||||
|
||||
@param seconds the duration in seconds.
|
||||
*/
|
||||
- (void)trackLaunchScreenDisplayDuration: (NSTimeInterval)seconds;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
Copyright 2018 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "Analytics.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
// All metrics are store under a Piwik category called "Metrics".
|
||||
// Then, there are 2 Piwik actions: "iOS.startup" and "iOS.stats" (these actions
|
||||
// are namespaced by plaform to have a nice rendering on the Piwik website).
|
||||
// Then, we use constants defined by the Matrix SDK as Piwik Names (ex:"mountData")
|
||||
NSString *const kAnalyticsPiwikMetricsCategory = @"Metrics";
|
||||
NSString *const kAnalyticsPiwikMetricsActionPattern = @"iOS.%@";
|
||||
|
||||
@import PiwikTracker;
|
||||
|
||||
@implementation Analytics
|
||||
|
||||
+ (instancetype)sharedInstance
|
||||
{
|
||||
static Analytics *sharedInstance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[Analytics alloc] init];
|
||||
});
|
||||
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (void)start
|
||||
{
|
||||
NSDictionary *piwikConfig = [[NSUserDefaults standardUserDefaults] objectForKey:@"piwik"];
|
||||
[PiwikTracker configureSharedInstanceWithSiteID:piwikConfig[@"siteId"]
|
||||
baseURL:[NSURL URLWithString:piwikConfig[@"url"]]
|
||||
userAgent:@"iOSPiwikTracker"];
|
||||
|
||||
// Check whether the user has enabled the sending of crash reports.
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"])
|
||||
{
|
||||
[PiwikTracker shared].isOptedOut = NO;
|
||||
|
||||
[[PiwikTracker shared] setCustomVariableWithIndex:1 name:@"App Platform" value:@"iOS Platform"];
|
||||
[[PiwikTracker shared] setCustomVariableWithIndex:2 name:@"App Version" value:[AppDelegate theDelegate].appVersion];
|
||||
|
||||
// The language is either the one selected by the user within the app
|
||||
// or, else, the one configured by the OS
|
||||
NSString *language = [NSBundle mxk_language] ? [NSBundle mxk_language] : [[NSBundle mainBundle] preferredLocalizations][0];
|
||||
[[PiwikTracker shared] setCustomVariableWithIndex:4 name:@"Chosen Language" value:language];
|
||||
|
||||
MXKAccount* account = [MXKAccountManager sharedManager].activeAccounts.firstObject;
|
||||
if (account)
|
||||
{
|
||||
[[PiwikTracker shared] setCustomVariableWithIndex:7 name:@"Homeserver URL" value:account.mxCredentials.homeServer];
|
||||
[[PiwikTracker shared] setCustomVariableWithIndex:8 name:@"Identity Server URL" value:account.identityServerURL];
|
||||
}
|
||||
|
||||
// TODO: We should also track device and os version
|
||||
// But that needs to be decided for all platforms
|
||||
|
||||
// Catch and log crashes
|
||||
[MXLogger logCrashes:YES];
|
||||
[MXLogger setBuildVersion:[AppDelegate theDelegate].build];
|
||||
|
||||
#ifdef DEBUG
|
||||
// Disable analytics in debug as it pollutes stats
|
||||
[PiwikTracker shared].isOptedOut = YES;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[AppDelegate] The user decided to not send analytics");
|
||||
[PiwikTracker shared].isOptedOut = YES;
|
||||
[MXLogger logCrashes:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stop
|
||||
{
|
||||
[PiwikTracker shared].isOptedOut = YES;
|
||||
[MXLogger logCrashes:NO];
|
||||
}
|
||||
|
||||
- (void)trackScreen:(NSString *)screenName
|
||||
{
|
||||
// Use the same pattern as Android
|
||||
NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
|
||||
NSString *appVersion = [AppDelegate theDelegate].appVersion;
|
||||
|
||||
[[PiwikTracker shared] trackWithView:@[@"ios", appName, appVersion, screenName]
|
||||
url:nil];
|
||||
}
|
||||
|
||||
- (void)dispatch
|
||||
{
|
||||
[[PiwikTracker shared] dispatch];
|
||||
}
|
||||
|
||||
- (void)trackLaunchScreenDisplayDuration:(NSTimeInterval)seconds
|
||||
{
|
||||
NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStartupCategory];
|
||||
|
||||
[[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory
|
||||
action:action
|
||||
name:kMXAnalyticsStartupLaunchScreen
|
||||
number:@(seconds * 1000)
|
||||
url:nil];
|
||||
}
|
||||
|
||||
#pragma mark - MXAnalyticsDelegate
|
||||
|
||||
- (void)trackStartupStorePreloadDuration: (NSTimeInterval)seconds
|
||||
{
|
||||
NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStartupCategory];
|
||||
|
||||
[[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory
|
||||
action:action
|
||||
name:kMXAnalyticsStartupStorePreload
|
||||
number:@(seconds * 1000)
|
||||
url:nil];
|
||||
}
|
||||
|
||||
- (void)trackStartupMountDataDuration: (NSTimeInterval)seconds
|
||||
{
|
||||
NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStartupCategory];
|
||||
|
||||
[[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory
|
||||
action:action
|
||||
name:kMXAnalyticsStartupMountData
|
||||
number:@(seconds * 1000)
|
||||
url:nil];
|
||||
}
|
||||
|
||||
- (void)trackStartupSyncDuration: (NSTimeInterval)seconds isInitial: (BOOL)isInitial
|
||||
{
|
||||
NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStartupCategory];
|
||||
|
||||
[[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory
|
||||
action:action
|
||||
name:isInitial ? kMXAnalyticsStartupInititialSync : kMXAnalyticsStartupIncrementalSync
|
||||
number:@(seconds * 1000)
|
||||
url:nil];
|
||||
}
|
||||
|
||||
- (void)trackRoomCount: (NSUInteger)roomCount
|
||||
{
|
||||
NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStatsCategory];
|
||||
|
||||
[[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory
|
||||
action:action
|
||||
name:kMXAnalyticsStatsRooms
|
||||
number:@(roomCount)
|
||||
url:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
+1
-6
@@ -22,6 +22,7 @@
|
||||
#import "JitsiViewController.h"
|
||||
|
||||
#import "RageShakeManager.h"
|
||||
#import "Analytics.h"
|
||||
|
||||
#import "RiotDesignValues.h"
|
||||
|
||||
@@ -128,12 +129,6 @@ extern NSString *const kAppDelegateNetworkStatusDidChangeNotification;
|
||||
|
||||
- (void)selectMatrixAccount:(void (^)(MXKAccount *selectedAccount))onSelection;
|
||||
|
||||
#pragma mark - Analytics
|
||||
|
||||
- (void)startAnalytics;
|
||||
- (void)stopAnalytics;
|
||||
- (void)trackScreen:(NSString*)screenName;
|
||||
|
||||
#pragma mark - Push notifications
|
||||
|
||||
- (void)registerUserNotificationSettings;
|
||||
|
||||
+10
-75
@@ -48,8 +48,6 @@
|
||||
|
||||
#import "WebViewViewController.h"
|
||||
|
||||
@import PiwikTracker;
|
||||
|
||||
// Calls
|
||||
#import "CallViewController.h"
|
||||
|
||||
@@ -235,10 +233,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
|
||||
MXSDKOptions *sdkOptions = [MXSDKOptions sharedInstance];
|
||||
sdkOptions.applicationGroupIdentifier = @"group.im.vector";
|
||||
|
||||
// Track SDK performance on Google analytics
|
||||
// TODO: needs the same tool
|
||||
//sdkOptions.analyticsDelegate = [[MXGoogleAnalytics alloc] init];
|
||||
|
||||
// Redirect NSLogs to files only if we are not debugging
|
||||
if (!isatty(STDERR_FILENO))
|
||||
{
|
||||
@@ -468,8 +462,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
// Configure Google Analytics here if the option is enabled
|
||||
[self startAnalytics];
|
||||
// Configure our analytics. It will indeed start if the option is enabled
|
||||
[MXSDKOptions sharedInstance].analyticsDelegate = [Analytics sharedInstance];
|
||||
[[Analytics sharedInstance] start];
|
||||
|
||||
// Prepare Pushkit handling
|
||||
_incomingPushEventIds = [NSMutableDictionary dictionary];
|
||||
@@ -563,7 +558,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
|
||||
_isAppForeground = NO;
|
||||
|
||||
// Analytics: Force to send the pending actions
|
||||
[[PiwikTracker shared] dispatch];
|
||||
[[Analytics sharedInstance] dispatch];
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application
|
||||
@@ -1026,70 +1021,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Analytics
|
||||
|
||||
- (void)startAnalytics
|
||||
{
|
||||
NSDictionary *piwikConfig = [[NSUserDefaults standardUserDefaults] objectForKey:@"piwik"];
|
||||
[PiwikTracker configureSharedInstanceWithSiteID:piwikConfig[@"siteId"]
|
||||
baseURL:[NSURL URLWithString:piwikConfig[@"url"]]
|
||||
userAgent:@"iOSPiwikTracker"];
|
||||
|
||||
// Check whether the user has enabled the sending of crash reports.
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"])
|
||||
{
|
||||
[PiwikTracker shared].isOptedOut = NO;
|
||||
|
||||
[[PiwikTracker shared] setCustomVariableWithIndex:1 name:@"App Platform" value:@"iOS Platform"];
|
||||
[[PiwikTracker shared] setCustomVariableWithIndex:2 name:@"App Version" value:[self appVersion]];
|
||||
|
||||
// The language is either the one selected by the user within the app
|
||||
// or, else, the one configured by the OS
|
||||
NSString *language = [NSBundle mxk_language] ? [NSBundle mxk_language] : [[NSBundle mainBundle] preferredLocalizations][0];
|
||||
[[PiwikTracker shared] setCustomVariableWithIndex:4 name:@"Chosen Language" value:language];
|
||||
|
||||
MXKAccount* account = [MXKAccountManager sharedManager].activeAccounts.firstObject;
|
||||
if (account)
|
||||
{
|
||||
[[PiwikTracker shared] setCustomVariableWithIndex:7 name:@"Homeserver URL" value:account.mxCredentials.homeServer];
|
||||
[[PiwikTracker shared] setCustomVariableWithIndex:8 name:@"Identity Server URL" value:account.identityServerURL];
|
||||
}
|
||||
|
||||
// TODO: We should also track device and os version
|
||||
// But that needs to be decided for all platforms
|
||||
|
||||
// Catch and log crashes
|
||||
[MXLogger logCrashes:YES];
|
||||
[MXLogger setBuildVersion:[AppDelegate theDelegate].build];
|
||||
|
||||
#ifdef DEBUG
|
||||
// Disable analytics in debug as it pollutes stats
|
||||
[PiwikTracker shared].isOptedOut = YES;
|
||||
#endif
|
||||
}
|
||||
else if ([[NSUserDefaults standardUserDefaults] objectForKey:@"enableCrashReport"])
|
||||
{
|
||||
NSLog(@"[AppDelegate] The user decided to not ");
|
||||
[PiwikTracker shared].isOptedOut = YES;
|
||||
[MXLogger logCrashes:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopAnalytics
|
||||
{
|
||||
[PiwikTracker shared].isOptedOut = YES;
|
||||
[MXLogger logCrashes:NO];
|
||||
}
|
||||
|
||||
- (void)trackScreen:(NSString *)screenName
|
||||
{
|
||||
// Use the same pattern as Android
|
||||
NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
|
||||
NSString *appVersion = [self appVersion];
|
||||
|
||||
[[PiwikTracker shared] trackWithView:@[@"ios", appName, appVersion, screenName]
|
||||
url:nil];
|
||||
}
|
||||
#pragma mark - Crash handling
|
||||
|
||||
// Check if there is a crash log to send to server
|
||||
- (void)checkExceptionToReport
|
||||
@@ -2914,8 +2846,11 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
|
||||
|
||||
if (launchAnimationContainerView)
|
||||
{
|
||||
NSTimeInterval durationMs = [[NSDate date] timeIntervalSinceDate:launchAnimationStart] * 1000;
|
||||
NSLog(@"[AppDelegate] LaunchAnimation was shown for %.3fms", durationMs);
|
||||
NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:launchAnimationStart];
|
||||
NSLog(@"[AppDelegate] LaunchAnimation was shown for %.3fms", duration * 1000);
|
||||
|
||||
// Track it on our analytics
|
||||
[[Analytics sharedInstance] trackLaunchScreenDisplayDuration:duration];
|
||||
|
||||
// TODO: Send durationMs to Piwik
|
||||
// Such information should be the same on all platforms
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"AttachmentsViewer"];
|
||||
[[Analytics sharedInstance] trackScreen:@"AttachmentsViewer"];
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"Authentication"];
|
||||
[[Analytics sharedInstance] trackScreen:@"Authentication"];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"GroupDetails"];
|
||||
[[Analytics sharedInstance] trackScreen:@"GroupDetails"];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"GroupDetailsHome"];
|
||||
[[Analytics sharedInstance] trackScreen:@"GroupDetailsHome"];
|
||||
|
||||
// Release the potential pushed view controller
|
||||
[self releasePushedViewController];
|
||||
|
||||
@@ -217,7 +217,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"GroupDetailsPeople"];
|
||||
[[Analytics sharedInstance] trackScreen:@"GroupDetailsPeople"];
|
||||
|
||||
// Release the potential pushed view controller
|
||||
[self releasePushedViewController];
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"GroupDetailsRooms"];
|
||||
[[Analytics sharedInstance] trackScreen:@"GroupDetailsRooms"];
|
||||
|
||||
// Release the potential pushed view controller
|
||||
[self releasePushedViewController];
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"Groups"];
|
||||
[[Analytics sharedInstance] trackScreen:@"Groups"];
|
||||
|
||||
// Deselect the current selected row, it will be restored on viewDidAppear (if any)
|
||||
NSIndexPath *indexPath = [self.groupsTableView indexPathForSelectedRow];
|
||||
|
||||
@@ -263,7 +263,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"ContactDetails"];
|
||||
[[Analytics sharedInstance] trackScreen:@"ContactDetails"];
|
||||
|
||||
// Hide the bottom border of the navigation bar to display the expander header
|
||||
[self hideNavigationBarBorder:YES];
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
@property (nonatomic) BOOL shouldScrollToTopOnRefresh;
|
||||
|
||||
/**
|
||||
The Google Analytics Instance screen name (Default is "ContactsTable").
|
||||
The analytics instance screen name (Default is "ContactsTable").
|
||||
*/
|
||||
@property (nonatomic) NSString *screenName;
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:_screenName];
|
||||
[[Analytics sharedInstance] trackScreen:_screenName];
|
||||
|
||||
// Check whether the access to the local contacts has not been already asked.
|
||||
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined)
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"CountryPicker"];
|
||||
[[Analytics sharedInstance] trackScreen:@"CountryPicker"];
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
|
||||
@@ -96,7 +96,7 @@ static CGFloat const kTextFontSize = 15.0;
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"DeactivateAccount"];
|
||||
[[Analytics sharedInstance] trackScreen:@"DeactivateAccount"];
|
||||
}
|
||||
|
||||
- (void)viewDidLayoutSubviews
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"DirectoryServerPicker"];
|
||||
[[Analytics sharedInstance] trackScreen:@"DirectoryServerPicker"];
|
||||
|
||||
// Observe kAppDelegateDidTapStatusBarNotificationObserver.
|
||||
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"Directory"];
|
||||
[[Analytics sharedInstance] trackScreen:@"Directory"];
|
||||
|
||||
// Observe kAppDelegateDidTapStatusBarNotificationObserver.
|
||||
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"FilesGlobalSearch"];
|
||||
[[Analytics sharedInstance] trackScreen:@"FilesGlobalSearch"];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshSearchResult:) name:kMXSessionDidLeaveRoomNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshSearchResult:) name:kMXSessionNewRoomNotification object:nil];
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"MessagesGlobalSearch"];
|
||||
[[Analytics sharedInstance] trackScreen:@"MessagesGlobalSearch"];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshSearchResult:) name:kMXSessionDidLeaveRoomNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshSearchResult:) name:kMXSessionNewRoomNotification object:nil];
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"CountryPicker"];
|
||||
[[Analytics sharedInstance] trackScreen:@"CountryPicker"];
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
// (Check whether 'enableCrashReport' flag has been set once)
|
||||
if (![[NSUserDefaults standardUserDefaults] objectForKey:@"enableCrashReport"])
|
||||
{
|
||||
[self promptUserBeforeUsingGoogleAnalytics];
|
||||
[self promptUserBeforeUsingAnalytics];
|
||||
}
|
||||
|
||||
[self refreshTabBarBadges];
|
||||
@@ -771,7 +771,7 @@
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)promptUserBeforeUsingGoogleAnalytics
|
||||
- (void)promptUserBeforeUsingAnalytics
|
||||
{
|
||||
NSLog(@"[MasterTabBarController]: Invite the user to send crash reports");
|
||||
|
||||
@@ -810,12 +810,12 @@
|
||||
typeof(self) self = weakSelf;
|
||||
self->currentAlert = nil;
|
||||
}
|
||||
|
||||
[[AppDelegate theDelegate] startAnalytics];
|
||||
|
||||
[[Analytics sharedInstance] start];
|
||||
|
||||
}]];
|
||||
|
||||
[currentAlert mxk_setAccessibilityIdentifier: @"HomeVCUseGoogleAnalyticsAlert"];
|
||||
[currentAlert mxk_setAccessibilityIdentifier: @"HomeVCUseAnalyticsAlert"];
|
||||
[self presentViewController:currentAlert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"MediaAlbumContent"];
|
||||
[[Analytics sharedInstance] trackScreen:@"MediaAlbumContent"];
|
||||
|
||||
self.navigationItem.title = _assetsCollection.localizedTitle;
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ static void *RecordingContext = &RecordingContext;
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"MediaPicker"];
|
||||
[[Analytics sharedInstance] trackScreen:@"MediaPicker"];
|
||||
|
||||
if (!userAlbumsQueue)
|
||||
{
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
@property (nonatomic) CGFloat stickyHeaderHeight;
|
||||
|
||||
/**
|
||||
The Google Analytics Instance screen name (Default is "RecentsScreen").
|
||||
The analytics instance screen name (Default is "RecentsScreen").
|
||||
*/
|
||||
@property (nonatomic) NSString *screenName;
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:_screenName];
|
||||
[[Analytics sharedInstance] trackScreen:_screenName];
|
||||
|
||||
// Deselect the current selected row, it will be restored on viewDidAppear (if any)
|
||||
NSIndexPath *indexPath = [self.recentsTableView indexPathForSelectedRow];
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"RoomFilesSearch"];
|
||||
[[Analytics sharedInstance] trackScreen:@"RoomFilesSearch"];
|
||||
|
||||
// Observe kAppDelegateDidTapStatusBarNotificationObserver.
|
||||
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
@@ -251,7 +251,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"RoomMemberDetails"];
|
||||
[[Analytics sharedInstance] trackScreen:@"RoomMemberDetails"];
|
||||
|
||||
// Hide the bottom border of the navigation bar to display the expander header
|
||||
[self hideNavigationBarBorder:YES];
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"RoomMessagesSearch"];
|
||||
[[Analytics sharedInstance] trackScreen:@"RoomMessagesSearch"];
|
||||
|
||||
// Observe kAppDelegateDidTapStatusBarNotificationObserver.
|
||||
kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
@@ -245,7 +245,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"RoomParticipants"];
|
||||
[[Analytics sharedInstance] trackScreen:@"RoomParticipants"];
|
||||
|
||||
if (memberDetailsViewController)
|
||||
{
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
}
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"RoomsSearch"];
|
||||
[[Analytics sharedInstance] trackScreen:@"RoomsSearch"];
|
||||
|
||||
// Enable the search field by default at the screen opening
|
||||
if (self.searchBarHidden)
|
||||
|
||||
@@ -289,7 +289,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"RoomSettings"];
|
||||
[[Analytics sharedInstance] trackScreen:@"RoomSettings"];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didUpdateRules:) name:kMXNotificationCenterDidUpdateRules object:nil];
|
||||
|
||||
|
||||
@@ -450,7 +450,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"ChatRoom"];
|
||||
[[Analytics sharedInstance] trackScreen:@"ChatRoom"];
|
||||
|
||||
// Refresh the room title view
|
||||
[self refreshRoomTitle];
|
||||
|
||||
@@ -423,7 +423,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"Settings"];
|
||||
[[Analytics sharedInstance] trackScreen:@"Settings"];
|
||||
|
||||
// Release the potential pushed view controller
|
||||
[self releasePushedViewController];
|
||||
@@ -2850,22 +2850,22 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
||||
BOOL enable = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"];
|
||||
if (enable)
|
||||
{
|
||||
NSLog(@"[SettingsViewController] disable automatic crash report sending");
|
||||
NSLog(@"[SettingsViewController] disable automatic crash report and analytics sending");
|
||||
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"enableCrashReport"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
[[AppDelegate theDelegate] stopAnalytics];
|
||||
[[Analytics sharedInstance] stop];
|
||||
|
||||
// Remove potential crash file.
|
||||
[MXLogger deleteCrashLog];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[SettingsViewController] enable automatic crash report sending");
|
||||
NSLog(@"[SettingsViewController] enable automatic crash report and analytics sending");
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"enableCrashReport"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
[[AppDelegate theDelegate] startAnalytics];
|
||||
[[Analytics sharedInstance] start];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"UnifiedSearch"];
|
||||
[[Analytics sharedInstance] trackScreen:@"UnifiedSearch"];
|
||||
|
||||
// Let's child display the loading not the home view controller
|
||||
if (self.activityIndicator)
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Screen tracking
|
||||
[[AppDelegate theDelegate] trackScreen:@"UnknowDevices"];
|
||||
[[Analytics sharedInstance] trackScreen:@"UnknowDevices"];
|
||||
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
@@ -114,19 +114,6 @@
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
<br/><br/>
|
||||
</li>
|
||||
<li>
|
||||
<b>GoogleAnalytics</b> (<a
|
||||
href="https://www.google.com/analytics">https://www.google.com/analytics</a>)
|
||||
<br/><br/>Measure your app performance.
|
||||
<br/><br/>Copyright (c) 2011-2016 Google Inc. All rights reserved.
|
||||
<br/><br/>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License at:
|
||||
<br/><br/><a
|
||||
href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>
|
||||
<br/><br/>Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||
<br/><br/>Google Analytics Terms of Service: <a
|
||||
href="https://www.google.com/analytics/terms">https://www.google.com/analytics/terms</a>
|
||||
<br/><br/>
|
||||
</li>
|
||||
<li>
|
||||
<b>GZIP</b> (<a
|
||||
href="https://github.com/nicklockwood/GZIP">https://github.com/nicklockwood/GZIP</a>)
|
||||
|
||||
Reference in New Issue
Block a user