smalls的头像

smalls

一个22岁的菜鸟程序员

我的技能

PHP

JAVA

JS

GO

PYTHON

ipa包签名过程
=================签名准备文件==================
首先是需要:xxxxx.p12
 
首先是需要:xxxx..mobileprovision
=============================================
 
①步骤
把 xxxxxx.p12 转换成   xxxx.cer  和  xxxx.pem
----------------------------------------------
①转换代码
 
openssl pkcs12 -in my.p12 -out xxx.pem -nodes
<得到:xxx.pem>两个任选一
 
openssl pkcs12 -clcerts -nokeys -out xxx.pem -in my.p12
<得到:xxx.pem>两个任选一
 
 
openssl pkcs12 -in my.p12 -out xxxx.crt -nokeys -clcerts
openssl x509 -inform pem -in xxxx.crt -outform der -out xxxx.cer
<得到:xxxx.cer>
 
========得到文件=保存起来=等会代码签名用===========
 
通过 xxxxx.p12转换
得到 xxxx.pem 
得到 xxxx.cer 
 
==================目前4个文件 列表===============
//自备文件
 
xxxxx.p12
xxxxx.mobileprovision
 
//通过xxx.p12转换得到文件
 
xxxx.pem
xxxx.cer
 
===============================================
 
//签名调用(xddSigning signIpaAtPath)
 
NSString *cachepath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
 
//签名保存文件路径
NSString *outputPath=[cachepath stringByAppendingPathComponent:@"Alook_qqqq_sign.ipa"];
        
 
//待签名文件路径<我是放到程序目录>线上可以读取Document
NSString *ipaPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Alook.ipa"];
        
 
[xddSigning signIpaAtPath:ipaPath outputPath:outputPath withCompletionHandler:^(NSError * error) {
    if(error){
        [xddCode xddLog:[NSString stringWithFormat:@"签名:%@",@"失败"]];
    }else{
        [xddCode xddLog:[NSString stringWithFormat:@"签名成功:路径=%@",outputPath]];
    }
 
}];
// signIpaAtPath 签名具体实现
+ (void)signIpaAtPath:(NSString*)ipaPath outputPath:(NSString*)outputPath withCompletionHandler:(void (^)(NSError *))completionHandler {
    
    // 1. Unpack IPA to a temporary directory.
    NSError *error;
    NSString *unpackedDirectory;
    if (![xddCode unpackIpaAtPath:ipaPath outDirectory:&unpackedDirectory error:&error]) {
        completionHandler(error);
        return;
    }
    
    // 2. Sign its main bundle via above method.
    // The bundle will be located at <temporarydirectory>/<zipfilename>/Payload/*.app internally
    
    NSString *zipFilename = [ipaPath lastPathComponent];
    zipFilename = [zipFilename stringByReplacingOccurrencesOfString:@".ipa" withString:@""];
    
    NSString *payloadDirectory = [NSString stringWithFormat:@"%@/Payload", unpackedDirectory];
    NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:payloadDirectory error:&error];
    
    if (error) {
        completionHandler(error);
        return;
    } else if (files.count == 0) {
        NSError *err = [xddCode _errorFromString:@"Payload directory of IPA has no contents"];
        completionHandler(err);
        return;
    }
    
    NSString *dotAppDirectory = @"";//获取程序包
    for (NSString *directory in files) {
        if ([directory containsString:@".app"]) {
            dotAppDirectory = directory;
            break;
        }
    }
    //...../Payload/xxxx.app
    NSString *bundleDirectory = [NSString stringWithFormat:@"%@/%@", payloadDirectory, dotAppDirectory];
    
    NSLog(@"Signing bundle at path '%@'", bundleDirectory);
 
    [xddCode xddLog:[NSString stringWithFormat:@"正在签名:%@",bundleDirectory]];
    //开始签名
    [self signBundleAtPath:bundleDirectory withCompletionHandler:^(NSError *err) {
        if (err) {
            completionHandler(err);
            return;
        }
        
        // 3. Repack IPA to output path
        NSError *error2;
        if (![xddCode repackIpaAtPath:[NSString stringWithFormat:@"%@/%@", [xddCode applicationTemporaryDirectory], zipFilename] toPath:outputPath error:&error2]) {
            completionHandler(error2);
        } else {
            // Success!
            completionHandler(nil);
            
            [xddCode xddLog:[NSString stringWithFormat:@"签名完毕:paAtPath=%@",[NSString stringWithFormat:@"%@/%@", [xddCode applicationTemporaryDirectory], zipFilename]]];
            [xddCode xddLog:[NSString stringWithFormat:@"签名完毕:toPath=%@",outputPath]];
            
        }
    }];
    
}
+ (void)signBundleAtPath:(NSString*)path withCompletionHandler:(void (^)(NSError *error))completionHandler {
    
    // We need to handle application extensions, e.g. watchOS applications and VPN plugins etc.
    // These are stored in the bundle's root directory at the following locations:
    // - /Plugins
    // - /Watch
    // Therefore, recurse through those directories as required before continuing for the root directory.
    
    dispatch_group_t dispatch_group = dispatch_group_create();
    NSMutableArray * __block subBundleErrors = [NSMutableArray array];
    
    if ([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithFormat:@"%@/PlugIns", path]]) {
        // Recurse through the plugins.
        
        for (NSString *subBundle in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[NSString stringWithFormat:@"%@/PlugIns", path] error:nil]) {
            NSString *__block subBundlePath = [NSString stringWithFormat:@"%@/PlugIns/%@", path, subBundle];
            
            // Enter the dispatch group
            dispatch_group_enter(dispatch_group);
            
            NSLog(@"Handling sub-bundle: %@", subBundlePath);
            
            // Sign the bundle
            [self signBundleAtPath:subBundlePath withCompletionHandler:^(NSError *error) {
                if (error)
                    [subBundleErrors addObject:error];
                
                NSLog(@"Finished sub-bundle: %@", subBundlePath);
                dispatch_group_leave(dispatch_group);
            }];
        }
    }
    
    if ([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithFormat:@"%@/Watch", path]]) {
        // Recurse through the watchOS stuff.
        
        for (NSString *subBundle in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[NSString stringWithFormat:@"%@/Watch", path] error:nil]) {
            NSString * __block subBundlePath = [NSString stringWithFormat:@"%@/Watch/%@", path, subBundle];
            
            // Enter the dispatch group
            dispatch_group_enter(dispatch_group);
            
            NSLog(@"Handling sub-bundle: %@", subBundlePath);
            
            // Sign the bundle
            [self signBundleAtPath:subBundlePath withCompletionHandler:^(NSError *error) {
                if (error)
                    [subBundleErrors addObject:error];
                
                NSLog(@"Handled sub-bundle: %@", subBundlePath);
                dispatch_group_leave(dispatch_group);
            }];
        }
    }
    
    // Wait on sub-bundles to finish, if needed.
     dispatch_group_wait(dispatch_group, DISPATCH_TIME_FOREVER);
    
    if (subBundleErrors.count > 0) {
        // Errors when handling sub-bundles!
        for (NSError *err in subBundleErrors) {
            NSLog(@"Error: %@", err.localizedDescription);
        }
        
        completionHandler([subBundleErrors lastObject]);
        return;
    }
    
    
    
    // 1. Read Info.plist to gain the applicationId and binaryLocation.
    // 2. Get provisioning profile and certificate info
    // 3. Sign bundle
    
    NSDictionary *infoplist = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", path]];
    
    if (!infoplist || [infoplist allKeys].count == 0) {
        NSError *error = [xddCode _errorFromString:@"Failed to open Info.plist!"];
        completionHandler(error);
        return;
    }
    
    // Find the systemType for this bundle.
    NSString *platformName = [infoplist objectForKey:@"DTPlatformName"];
    EESystemType systemType = -1;
    if ([platformName isEqualToString:@"iphoneos"]) {
        systemType = EESystemTypeiOS;
    } else if ([platformName isEqualToString:@"watchos"]) {
        systemType = EESystemTypewatchOS;
    } else if ([platformName isEqualToString:@"tvos"]) {
        systemType = EESystemTypetvOS;
    } else {
        // Base case, assume iOS.
        systemType = EESystemTypeiOS;
    }
    
    NSLog(@"Platform: %@ for bundle: %@", platformName, [path lastPathComponent]);
    
    NSString *applicationId = [infoplist objectForKey:@"CFBundleIdentifier"];
    NSString *binaryLocation = [path stringByAppendingFormat:@"/%@", [infoplist objectForKey:@"CFBundleExecutable"]];
    
    
    
    NSLog(@"applicationId: %@ for bundle: %@", applicationId, [path lastPathComponent]);
    NSLog(@"binaryLocation: %@ for bundle: %@", binaryLocation, [path lastPathComponent]);
    
    
    // We get entitlements from the binary using ldid::Analyze() during provisioning, updating them as needed
    // for the current Team ID.
    {
        // We now have a valid provisioning profile for this application!
        // And, we also have a valid development codesigning certificate, with its private key!
        
        // Add embedded.mobileprovision to the bundle, overwriting if needed.
        NSError *fileIOError;
        NSString *embeddedPath = [NSString stringWithFormat:@"%@/embedded.mobileprovision", path];
        
        NSLog(@"embeddedPath=%@", embeddedPath);
        //删除旧签名文件
        if ([[NSFileManager defaultManager] fileExistsAtPath:embeddedPath]) {
            [[NSFileManager defaultManager] removeItemAtPath:embeddedPath error:&fileIOError];
            
            if (fileIOError) {
                NSLog(@"removeItemAtPath%@", fileIOError);
                return;
            }
        }
        
        //写入新的
        NSString *mobileprovisionFileName = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Web/qqqq.mobileprovision"];
        //最后:从文件中读出 xxxx.mobileprovision
        NSData *embeddedMobileProvision = [NSData dataWithContentsOfFile:mobileprovisionFileName options:0 error:NULL];
        if (![(NSData*)embeddedMobileProvision writeToFile:embeddedPath options:NSDataWritingAtomic error:&fileIOError]) {
            
            if (fileIOError) {
                NSLog(@"writeToFile err:%@", fileIOError);
            } else {
                NSLog(@"writeToFile Failed to write '%@'.", embeddedPath);
            }
            return;
        }
        
        // Next step: signing. To do this, we use EESigner with these four results.
        NSString *p12FileName = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Web/qqqq.cer"];
        //从文件中读出 配置文件 xxxx.cer
        NSData *p12Provision = [NSData dataWithContentsOfFile:p12FileName options:0 error:NULL];//从FileName中读取出数据
        
        //从文件中读出 秘钥 xxxx.pem
        NSString *ProvisionFileName = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Web/qqqq.pem"];
        NSData *ProvisionNsData = [[NSData alloc] initWithContentsOfFile:ProvisionFileName];
        NSString *privateKey = [[NSString alloc] initWithData:ProvisionNsData  encoding:NSUTF8StringEncoding];
        
        //获取 Entitlements
        NSDictionary* entitlements = [xddCode getEntitlements:mobileprovisionFileName];
        
        //创建签名类signer
        EESigning *signer =  [EESigning signerWithCertificate:p12Provision privateKey:privateKey];
        //EESigning *signer =  [NSClassFromString(@"EESigning") signerWithCertificate:p12Provision privateKey:privateKey];
        
        //调用签名开始
        [signer signBundleAtPath:path entitlements:entitlements identifier:applicationId withCallback:^(BOOL success, NSString *result) {
            
            NSLog(@"signBundleAtPath.result=%@", result);
            
            NSString*title = @"成功";
            NSError *error = nil;
            if (!success) {
                title = @"失败";
            }
            
            [xddCode xddLog:[NSString stringWithFormat:@"signBundleAtPath title=%@,result=%@",title,result]];
            
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                
                // We will now pause so that ldid can cleanup after itself.
                [NSThread sleepForTimeInterval:1];
                
                NSError *error = nil;
                if (!success) {
                    error = [xddCode _errorFromString:result];
                }
                
                // We're done.
                completionHandler(error);
            });
            
            
        }];
        
        
        
    }
    
    
}
给作者打赏一下吧

文章评论

暂无评论
留言板
评论