blob: ab6c2925f42b313a0148663166d81bf811822be4 (
plain) (
blame)
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
|
#import <Foundation/Foundation.h>
#import "LSApplicationProxy+AltList.h"
@implementation LSApplicationProxy (AltList)
// the tag " hidden " is also valid, so we need to check if any strings contain "hidden" instead
BOOL tagArrayContainsTag(NSArray* tagArr, NSString* tag)
{
if(!tagArr || !tag) return NO;
__block BOOL found = NO;
[tagArr enumerateObjectsUsingBlock:^(NSString* tagToCheck, NSUInteger idx, BOOL* stop)
{
if(![tagToCheck isKindOfClass:[NSString class]])
{
return;
}
if([tagToCheck rangeOfString:tag options:0].location != NSNotFound)
{
found = YES;
*stop = YES;
}
}];
return found;
}
// always returns NO on iOS 7
- (BOOL)atl_isHidden
{
NSArray* appTags;
NSArray* recordAppTags;
NSArray* sbAppTags;
BOOL launchProhibited = NO;
if([self respondsToSelector:@selector(correspondingApplicationRecord)])
{
// On iOS 14, self.appTags is always empty but the application record still has the correct ones
LSApplicationRecord* record = [self correspondingApplicationRecord];
recordAppTags = record.appTags;
launchProhibited = record.launchProhibited;
}
if([self respondsToSelector:@selector(appTags)])
{
appTags = self.appTags;
}
if(!launchProhibited && [self respondsToSelector:@selector(isLaunchProhibited)])
{
launchProhibited = self.launchProhibited;
}
NSURL* bundleURL = self.bundleURL;
if(bundleURL && [bundleURL checkResourceIsReachableAndReturnError:nil])
{
NSBundle* bundle = [NSBundle bundleWithURL:bundleURL];
sbAppTags = [bundle objectForInfoDictionaryKey:@"SBAppTags"];
}
BOOL isWebApplication = ([self.bundleIdentifier rangeOfString:@"com.apple.webapp" options:NSCaseInsensitiveSearch].location != NSNotFound);
return tagArrayContainsTag(appTags, @"hidden") || tagArrayContainsTag(recordAppTags, @"hidden") || tagArrayContainsTag(sbAppTags, @"hidden") || isWebApplication || launchProhibited;
}
// Getting the display name is slow (up to 2ms) because it uses an IPC call
// this stacks up if you do it for every single application
// This method provides a faster way (around 0.5ms) to get the display name
// This reduces the overall time needed to sort the applications from ~230 to ~120ms on my test device
- (NSString*)atl_fastDisplayName
{
NSString* cachedDisplayName = [self valueForKey:@"_localizedName"];
if(cachedDisplayName && ![cachedDisplayName isEqualToString:@""])
{
return cachedDisplayName;
}
NSString* localizedName;
NSURL* bundleURL = self.bundleURL;
if(!bundleURL || ![bundleURL checkResourceIsReachableAndReturnError:nil])
{
localizedName = self.localizedName;
}
else
{
NSBundle* bundle = [NSBundle bundleWithURL:bundleURL];
localizedName = [bundle objectForInfoDictionaryKey:@"CFBundleDisplayName"];
if(![localizedName isKindOfClass:[NSString class]]) localizedName = nil;
if(!localizedName || [localizedName isEqualToString:@""])
{
localizedName = [bundle objectForInfoDictionaryKey:@"CFBundleName"];
if(![localizedName isKindOfClass:[NSString class]]) localizedName = nil;
if(!localizedName || [localizedName isEqualToString:@""])
{
localizedName = [bundle objectForInfoDictionaryKey:@"CFBundleExecutable"];
if(![localizedName isKindOfClass:[NSString class]]) localizedName = nil;
if(!localizedName || [localizedName isEqualToString:@""])
{
//last possible fallback: use slow IPC call
localizedName = self.localizedName;
}
}
}
}
[self setValue:localizedName forKey:@"_localizedName"];
return localizedName;
}
- (NSString*)atl_nameToDisplay
{
NSString* localizedName = [self atl_fastDisplayName];
if([self.bundleIdentifier rangeOfString:@"carplay" options:NSCaseInsensitiveSearch].location != NSNotFound)
{
if([localizedName rangeOfString:@"carplay" options:NSCaseInsensitiveSearch range:NSMakeRange(0, localizedName.length) locale:[NSLocale currentLocale]].location == NSNotFound)
{
return [localizedName stringByAppendingString:@" (CarPlay)"];
}
}
return localizedName;
}
@end
|