Merge remote-tracking branch 'origin/develop' into feature/xcode8-beta6

# Conflicts:
#	Classes/BITHockeyHelper.m
This commit is contained in:
Benjamin Scholtysik (Reimold)
2016-09-06 10:43:53 -07:00
12 changed files with 144 additions and 20 deletions

View File

@@ -25,6 +25,7 @@ before_install:
- brew install carthage
script:
- open -b com.apple.iphonesimulator
- set -o pipefail
- COMMAND="env NSUnbufferedIO=YES xcodebuild -project '$PROJECT' -scheme '$SCHEME' -sdk '$SDK' -configuration '$CONFIGURATION'"

View File

@@ -220,15 +220,18 @@
// File extension that suits the Content type.
CFStringRef mimeType = (__bridge CFStringRef)self.contentType;
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
CFStringRef extension = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension);
if (extension) {
_tempFilename = [_tempFilename stringByAppendingPathExtension:(__bridge NSString *)(extension)];
CFRelease(extension);
if (mimeType) {
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
CFStringRef extension = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension);
if (extension) {
_tempFilename = [_tempFilename stringByAppendingPathExtension:(__bridge NSString *)(extension)];
CFRelease(extension);
}
if (uti) {
CFRelease(uti);
}
}
CFRelease(uti);
return _tempFilename;
}

View File

@@ -634,15 +634,21 @@ NSString *bit_validAppIconStringFromIcons(NSBundle *resourceBundle, NSArray *ico
// Don't use imageNamed, otherwise unit tests won't find the fixture icon
// and using imageWithContentsOfFile doesn't load @2x files with absolut paths (required in tests)
NSString *iconPathExtension = ([[icon pathExtension] length] > 0) ? [icon pathExtension] : @"png";
NSMutableArray *iconFilenameVariants = [NSMutableArray new];
[iconFilenameVariants addObject:icon];
[iconFilenameVariants addObject:[NSString stringWithFormat:@"%@@2x", icon]];
[iconFilenameVariants addObject:[icon stringByDeletingPathExtension]];
[iconFilenameVariants addObject:[NSString stringWithFormat:@"%@@2x", [icon stringByDeletingPathExtension]]];
for (NSString *iconFilename in iconFilenameVariants) {
// this call already covers "~ipad" files
NSString *iconPath = [resourceBundle pathForResource:iconFilename ofType:iconPathExtension];
NSString *iconPath = [resourceBundle pathForResource:iconFilename ofType:@"png"];
if (!iconPath && (icon.pathExtension.length > 0)) {
iconPath = [resourceBundle pathForResource:iconFilename ofType:icon.pathExtension];
}
NSData *imgData = [[NSData alloc] initWithContentsOfFile:iconPath];
@@ -679,15 +685,13 @@ NSString *bit_validAppIconFilename(NSBundle *bundle, NSBundle *resourceBundle) {
}
// we test iPad structure anyway and use it if we find a result and don't have another one yet
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
if (!iconFilename && (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)) {
icons = [bundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"];
if (icons && [icons isKindOfClass:[NSDictionary class]]) {
icons = [icons valueForKeyPath:@"CFBundlePrimaryIcon.CFBundleIconFiles"];
}
NSString *iPadIconFilename = bit_validAppIconStringFromIcons(resourceBundle, icons);
if (iPadIconFilename && !iconFilename) {
iconFilename = iPadIconFilename;
}
iconFilename = iPadIconFilename;
}
if (!iconFilename) {

View File

@@ -424,7 +424,7 @@ and set the delegate:
HockeyApp automatically provides you with nice, intelligible, and informative metrics about how your app is used and by whom.
- **Sessions**: A new session is tracked by the SDK whenever the containing app is restarted (this refers to a 'cold start', i.e. when the app has not already been in memory prior to being launched) or whenever it becomes active again after having been in the background for 20 seconds or more.
- **Users**: The SDK anonymously tracks the users of your app by creating a random UUID that is then securely stored in the iOS keychain. Because this anonymous ID is stored in the keychain it persists across reinstallations.
- **Custom Events**: If you are part of [Preseason](https://www.hockeyapp.net/preseason/), you can now track Custom Events in your app, understand user actions and see the aggregates on the HockeyApp portal.
- **Custom Events**: With HockeySDK 4.1.0 you can now track Custom Events in your app, understand user actions and see the aggregates on the HockeyApp portal.
Just in case you want to opt-out of the automatic collection of anonymous users and sessions statistics, there is a way to turn this functionality off at any time:

View File

@@ -386,6 +386,12 @@
80807B8E1C46BF2F00F4C44F /* OCMockitoIOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80807B8B1C46BF2F00F4C44F /* OCMockitoIOS.framework */; };
80807B8F1C46BF2F00F4C44F /* OCMockitoIOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80807B8B1C46BF2F00F4C44F /* OCMockitoIOS.framework */; };
80807B901C46C01E00F4C44F /* BITUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 8034E6681BA31D7C00D83A30 /* BITUser.m */; };
8085BB851CBF1FA60023FD9B /* AppIcon.exotic.png in Resources */ = {isa = PBXBuildFile; fileRef = 8085BB831CBF1FA60023FD9B /* AppIcon.exotic.png */; };
8085BB861CBF1FA60023FD9B /* AppIcon.exotic.png in Resources */ = {isa = PBXBuildFile; fileRef = 8085BB831CBF1FA60023FD9B /* AppIcon.exotic.png */; };
8085BB871CBF1FA60023FD9B /* AppIcon.exotic@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8085BB841CBF1FA60023FD9B /* AppIcon.exotic@2x.png */; };
8085BB881CBF1FA60023FD9B /* AppIcon.exotic@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8085BB841CBF1FA60023FD9B /* AppIcon.exotic@2x.png */; };
8085BB8A1CBF216E0023FD9B /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 8085BB891CBF216E0023FD9B /* Icon.png */; };
8085BB8B1CBF216E0023FD9B /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 8085BB891CBF216E0023FD9B /* Icon.png */; };
80A4662F1C58F4DF00199909 /* BITCrashReportTextFormatterPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 80A4662D1C58F4DF00199909 /* BITCrashReportTextFormatterPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
80B1C4EE1C8A6F950057A5CB /* BITUser.h in Headers */ = {isa = PBXBuildFile; fileRef = 8034E6671BA31D7C00D83A30 /* BITUser.h */; };
80B1C4EF1C8A72620057A5CB /* HockeySDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EB6173F1B0A30480035A986 /* HockeySDK.framework */; };
@@ -705,6 +711,9 @@
808441721C20617C00644A40 /* OCMockObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMockObject.h; sourceTree = "<group>"; };
808441731C20617C00644A40 /* OCMRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMRecorder.h; sourceTree = "<group>"; };
808441741C20617C00644A40 /* OCMStubRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMStubRecorder.h; sourceTree = "<group>"; };
8085BB831CBF1FA60023FD9B /* AppIcon.exotic.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = AppIcon.exotic.png; sourceTree = "<group>"; };
8085BB841CBF1FA60023FD9B /* AppIcon.exotic@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "AppIcon.exotic@2x.png"; sourceTree = "<group>"; };
8085BB891CBF216E0023FD9B /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = "<group>"; };
80A4662D1C58F4DF00199909 /* BITCrashReportTextFormatterPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashReportTextFormatterPrivate.h; sourceTree = "<group>"; };
80CA63881C67BD5400362DBF /* libOCMock.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libOCMock.a; sourceTree = "<group>"; };
80CA638E1C67F78000362DBF /* BITUpdateManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITUpdateManagerTests.m; sourceTree = "<group>"; };
@@ -1030,6 +1039,9 @@
children = (
1E494AEA19491943001EFF74 /* AppIcon.png */,
1E494AEB19491943001EFF74 /* AppIcon@2x.png */,
8085BB831CBF1FA60023FD9B /* AppIcon.exotic.png */,
8085BB841CBF1FA60023FD9B /* AppIcon.exotic@2x.png */,
8085BB891CBF216E0023FD9B /* Icon.png */,
1EA1170316F53B49001C015C /* StoreBundleIdentifierUnknown.json */,
1EA1170816F53E3A001C015C /* StoreBundleIdentifierKnown.json */,
1E70A22F17F2F982001BB32D /* live_report_empty.plcrash */,
@@ -1689,6 +1701,8 @@
buildActionMask = 2147483647;
files = (
1E85C5621B3438EB00CE2C0D /* live_report_exception_marketing.plcrash in Resources */,
8085BB871CBF1FA60023FD9B /* AppIcon.exotic@2x.png in Resources */,
8085BB851CBF1FA60023FD9B /* AppIcon.exotic.png in Resources */,
1E494AEC19491943001EFF74 /* AppIcon.png in Resources */,
1E85C5631B3438EB00CE2C0D /* live_report_signal_marketing.plcrash in Resources */,
1EA1170C16F54A64001C015C /* HockeySDKResources.bundle in Resources */,
@@ -1700,6 +1714,7 @@
6EA5DEAE1CC0670000D44206 /* log_report_xamarin in Resources */,
1E70A23217F2F982001BB32D /* live_report_empty.plcrash in Resources */,
1E494AED19491943001EFF74 /* AppIcon@2x.png in Resources */,
8085BB8A1CBF216E0023FD9B /* Icon.png in Resources */,
1EA1170916F53E3A001C015C /* StoreBundleIdentifierKnown.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1717,6 +1732,8 @@
buildActionMask = 2147483647;
files = (
1E85C5641B3438EC00CE2C0D /* live_report_exception_marketing.plcrash in Resources */,
8085BB881CBF1FA60023FD9B /* AppIcon.exotic@2x.png in Resources */,
8085BB861CBF1FA60023FD9B /* AppIcon.exotic.png in Resources */,
1E1508871B0C946700D7B9D9 /* AppIcon.png in Resources */,
1E85C5651B3438EC00CE2C0D /* live_report_signal_marketing.plcrash in Resources */,
1E1508891B0C946700D7B9D9 /* StoreBundleIdentifierUnknown.json in Resources */,
@@ -1728,6 +1745,7 @@
6EA5DEAF1CC0670000D44206 /* log_report_xamarin in Resources */,
1E15088A1B0C946700D7B9D9 /* StoreBundleIdentifierKnown.json in Resources */,
1E15088E1B0C946D00D7B9D9 /* InfoPlist.strings in Resources */,
8085BB8B1CBF216E0023FD9B /* Icon.png in Resources */,
1E15088C1B0C946700D7B9D9 /* live_report_exception.plcrash in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>classNames</key>
<dict>
<key>BITHockeyHelperTests</key>
<dict>
<key>testValidAppIconFilenamePerformance</key>
<dict>
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
<dict>
<key>baselineAverage</key>
<real>0.6</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
</dict>
</dict>
</dict>
</dict>
</plist>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>runDestinationsByUUID</key>
<dict>
<key>E1AF7159-3C8D-4A2A-8625-B72024F5DD3E</key>
<dict>
<key>localComputer</key>
<dict>
<key>busSpeedInMHz</key>
<integer>100</integer>
<key>cpuCount</key>
<integer>1</integer>
<key>cpuKind</key>
<string>Intel Core i7</string>
<key>cpuSpeedInMHz</key>
<integer>2800</integer>
<key>logicalCPUCoresPerPackage</key>
<integer>8</integer>
<key>modelCode</key>
<string>MacBookPro11,3</string>
<key>physicalCPUCoresPerPackage</key>
<integer>4</integer>
<key>platformIdentifier</key>
<string>com.apple.platform.macosx</string>
</dict>
<key>targetArchitecture</key>
<string>x86_64</string>
<key>targetDevice</key>
<dict>
<key>modelCode</key>
<string>iPhone8,1</string>
<key>platformIdentifier</key>
<string>com.apple.platform.iphonesimulator</string>
</dict>
</dict>
</dict>
</dict>
</plist>

View File

@@ -101,6 +101,19 @@
NSString *resultString = nil;
NSBundle *mockBundle = mock([NSBundle class]);
NSBundle *resourceBundle = [NSBundle bundleForClass:self.class];
// CFBundleIcons contains exotic dictionary filenames
NSString *exoticValidIconPath = @"AppIcon.exotic";
NSString *exoticValidIconPath2x = @"AppIcon.exotic@2x";
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFiles"]) willReturn:@[@"invalidFilename.png"]];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons"]) willReturn:@{@"CFBundlePrimaryIcon":@{@"CFBundleIconFiles":@[exoticValidIconPath, exoticValidIconPath2x]}}];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"]) willReturn:nil];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:nil];
//resultString = bit_validAppIconFilename(mockBundle, resourceBundle);
//assertThat(resultString, equalTo(exoticValidIconPath2x));
// Regular icon names
NSString *validIconPath = @"AppIcon";
NSString *validIconPath2x = @"AppIcon@2x";
@@ -111,7 +124,7 @@
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:@"invalidFilename.png"];
resultString = bit_validAppIconFilename(mockBundle, resourceBundle);
assertThat(resultString, nilValue());
assertThat(resultString, equalTo(@"Icon"));
// CFBundleIconFiles contains valid filenames
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFiles"]) willReturn:@[validIconPath, validIconPath2x]];
@@ -120,14 +133,14 @@
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:nil];
resultString = bit_validAppIconFilename(mockBundle, resourceBundle);
assertThat(resultString, notNilValue());
assertThat(resultString, equalTo(validIconPath2x));
// CFBundleIcons contains valid dictionary filenames
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFiles"]) willReturn:@[@"invalidFilename.png"]];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons"]) willReturn:@{@"CFBundlePrimaryIcon":@{@"CFBundleIconFiles":@[validIconPath, validIconPath2x]}}];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"]) willReturn:nil];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:nil];
// CFBundleIcons contains valid ipad dictionary and valid default dictionary filenames
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFiles"]) willReturn:@[@"invalidFilename.png"]];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons"]) willReturn:@{@"CFBundlePrimaryIcon":@{@"CFBundleIconFiles":@[validIconPath, validIconPath2x]}}];
@@ -135,7 +148,7 @@
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:nil];
resultString = bit_validAppIconFilename(mockBundle, resourceBundle);
assertThat(resultString, notNilValue());
assertThat(resultString, equalTo(validIconPath2x));
// CFBundleIcons contains valid filenames
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFiles"]) willReturn:@[@"invalidFilename.png"]];
@@ -144,7 +157,7 @@
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:nil];
resultString = bit_validAppIconFilename(mockBundle, resourceBundle);
assertThat(resultString, notNilValue());
assertThat(resultString, equalTo(validIconPath2x));
// CFBundleIcon contains valid filename
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFiles"]) willReturn:@[@"invalidFilename.png"]];
@@ -153,9 +166,29 @@
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:validIconPath];
resultString = bit_validAppIconFilename(mockBundle, resourceBundle);
assertThat(resultString, notNilValue());
assertThat(resultString, equalTo(validIconPath2x));
}
#ifndef CI
- (void)testValidAppIconFilenamePerformance {
NSBundle *mockBundle = mock([NSBundle class]);
NSBundle *resourceBundle = [NSBundle bundleForClass:self.class];
NSString *validIconPath2x = @"AppIcon@2x";
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFiles"]) willReturn:nil];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons"]) willReturn:nil];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIcons~ipad"]) willReturn:nil];
[given([mockBundle objectForInfoDictionaryKey:@"CFBundleIconFile"]) willReturn:validIconPath2x];
[self measureBlock:^{
for (int i = 0; i < 1000; i++) {
__unused NSString *resultString = bit_validAppIconFilename(mockBundle, resourceBundle);
}
}];
}
#endif
- (void)testDevicePlattform {
NSString *resultString = bit_devicePlatform();
assertThat(resultString, notNilValue());

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,3 +1,6 @@
## 4.1.1
- [BUGFIX] Fix app icons with unusual filenames not showing in the in-app update prompt
## 4.1.0
- Includes improvements from 4.0.2 release of the SDK.