Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASIdentifierManager is not found in iOS12

I m writing here cos I'm really stuck and can't find an answer.

We have a small framework who can collect IDFA inside. For IDFA collection first at all we checks NSClassFromString(@"ASIdentifierManager")

The problem is:

Imagine we have a client and this client released version for iOS10-iOS12. And this client gets IDFA for iOS10 and iOS11, but for all iOS12 there is no IDFA at all! After logs checked we have found that NSClassFromString(@"ASIdentifierManager") is nil only for iOS12..

How the client could add a framework for iOS10, 11 but not for iOS12?

On the other hand, another client is doing well with iOS12.

like image 991
Andrey Gagan Avatar asked Nov 14 '18 10:11

Andrey Gagan


1 Answers

This may not answer your question completely, just text what I know and my guess.

First, the dynamic frameworks won't be loaded in your app process until you use it, such as the frameworks under the directory which are available in iOS with simulator device.

> cd /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks
> # Now there are plenty of frameworks here.
> file  AdSupport.framework/AdSupport
Mach-O 64-bit dynamically linked shared library x86_64

How to use it? TLDR, call it with [ASIdentifierManager sharedManager] in your app anywhere, link against the framework firstly and compile it successfully, of course.

Second, what's the difference between using NSClassFromString() directly and calling [ASIdentifierManager sharedManager] anywhere?

For the former case, your application won't load the AdSupport framework bundle since there are not symbol named ASIdentifierManager in your executable program when the os kernel loads your program, it can be proved by print your app main bundle path and find the app executable file, try to nm <path/to/executable_app> | grep "ASIdentifierManager", nothing will be found in result since you didn't use it.

For the latter one, try to grep the same symbol in the executable program, there it is.

Note: it's not os kernel loads the frameworks by nm result list but the kernel loads the frameworks containing the symbols, check out more info about the dynamic loader dyld.

Third, NSClassFromString only checks the loaded classes, if the AdSupport framework doesn't be loaded, it returns nil without trying to load the framework containing the target class.

Forth, it's impossible to recall the difference between in iOS 10/11 and iOS 12 until you paste out more context about the IDFA and AdSupport framework usage in your project. Here is my one guess, some of the dependent libraries use the AdSupport framework in the early version but iOS 12, you have to try to dump the symbol list between in iOS 11 and iOS 12 and compare the result.

Fifth, I'm not sure what you want, maybe you're trying to avoid importing AdSupport framework explicitly, how about initializing a NSBundle by framework path and call the -(BOOL)load of NSBundle class, then you could get the Class object with NSClassFromString.

UPDATE:

NSString *strFrameworkPath = nil;

#if TARGET_OS_SIMULATOR
strFrameworkPath = [[NSProcessInfo processInfo] environment][@"DYLD_FALLBACK_FRAMEWORK_PATH"];
#else
// Assume that the AdSupport and Foundation framework are in the same directory.
strFrameworkPath = [NSBundle bundleForClass:NSPredicate.class].bundlePath;
strFrameworkPath = [strFrameworkPath stringByDeletingLastPathComponent];
#endif

strFrameworkPath = [strFrameworkPath stringByAppendingPathComponent:@"AdSupport.framework"];
NSAssert([[NSFileManager defaultManager] fileExistsAtPath:strFrameworkPath], @"Invalid framework bundle path!");

NSBundle *bundle = [NSBundle bundleWithPath:strFrameworkPath];

if (!bundle.isLoaded) {
    NSError *error = nil;

    if (![bundle loadAndReturnError:&error]) {
        DDLogError(@"Load framework bundle %@ with error %@", bundle, error);
    }
}

DDLogDebug(@"bundle: %@", bundle.bundlePath);
DDLogDebug(@"class: %@", NSClassFromString(@"ASIdentifierManager"));

You may need to enhance the compatibility of kinds of the device for products, for more details about the NSBundle usage, check out the official documentation here.

like image 132
Itachi Avatar answered Oct 26 '22 17:10

Itachi