介绍
引自Apple
App 正在改变世界,丰富人们的生活,并为像您一样的开发者提供前所未有的创新机会。因此,App Store 已成长为一个激动人心且充满活力的生态系统,正为数百万的开发者和超过十亿的用户提供服务。不管是开发新手,还是由经验丰富的程序员所组成的大型团队,我们都非常欢迎您为 App Store 开发 app,并希望能够帮助您了解我们的准则,以确保您的 app 能够快速通过审核流程。
原因
苹果审核规则很多,有时候一直正常提包,某一天换了一个审核人员,提审的包就被拒了。给的原因莫名其妙,自查很难定位到原因,改完能不能过,全靠运气。
为了能够更好的过审,需要能全面监控苹果审核人员的操作,记录下来,并通过机器人接口上报钉钉群。
钉钉机器人设置
操作路径
群设置-智能群助手-添加机器人-自定义【通过Webhook接入自定义服务】
设置机器人
自定义关键词begin
记录Webhook地址
https://oapi.dingtalk.com/robot/send?access_token=xxx
代码实现
判断uid是否是提审的,如果是,开始记录操作路径并上报,调用reportText
这个接口
+ (BOOL)isApple {
NSString *uid = [[[NSBundle mainBundle] infoDictionary] valueForKeyPath:@"Appconfig.alppeReivwUid"];
if ([[IKAtomFactory sharedInstance].atom.userId isEqualToString:uid]) {
return YES;
}
return NO;
}
实现如下
//
// CJMtinorAlplpeReivw.m
// AFNetworking
//
// Created by jackyshan on 2019/11/12.
//
#import "CJMtinorAlplpeReivw.h"
#import <RSSwizzle/RSSwizzle.h>
@interface CJMtinorAlplpeReivw()
/** 上报队列 */
@property (nonatomic, strong) NSMutableArray *textMArr;
@property (nonatomic, strong) dispatch_source_t gcdTimer;
@property (nonatomic, assign) NSInteger takeTime;// 花费时长
@property(nonatomic, copy) NSString *bundleShortVersionString;
@property(nonatomic, copy) NSString *bundleVersion;
+ (instancetype)sharedInstance;
@end
@implementation CJMtinorAlplpeReivw
+ (instancetype)sharedInstance {
static CJMtinorAlplpeReivw *_sharedIns = nil;
if (_sharedIns == nil) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedIns = [[[self class] alloc] init];
});
}
return _sharedIns;
}
- (instancetype)init {
if (self = [super init]) {
_textMArr = [NSMutableArray array];
[self startTimer];
}
return self;
}
- (void)startTimer {
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
if (timer) {
dispatch_source_set_timer(timer, dispatch_walltime(DISPATCH_TIME_NOW, NSEC_PER_SEC * 1), 3 *NSEC_PER_SEC, NSEC_PER_SEC * 1);
dispatch_source_set_event_handler(timer, ^{
[[CJMtinorAlplpeReivw sharedInstance] uploadTextQueue];
self.takeTime += 3;
});
dispatch_resume(timer);
self.gcdTimer = timer;
}
}
- (void)uploadTextQueue {
if (![CJMtinorAlplpeReivw isApple]) {
return;
}
if ([CJMtinorAlplpeReivw sharedInstance].textMArr.count == 0) {
return;
}
NSString *content = [NSString stringWithFormat:@"begin %@\n%@(%@)\ntt:%zds",[[NSBundle mainBundle] bundleIdentifier],self.bundleShortVersionString,self.bundleVersion,self.takeTime];
for (NSString *text in [CJMtinorAlplpeReivw sharedInstance].textMArr) {
content = [NSString stringWithFormat:@"%@\n%@", content, text?:@""];
}
[[CJMtinorAlplpeReivw sharedInstance].textMArr removeAllObjects];
NSString *atoken = [[[NSBundle mainBundle] infoDictionary] valueForKeyPath:@"Appconfig.ddingtoken"];
if (atoken.length == 0) {
return;
}
NSString *urStr = [NSString stringWithFormat:@"https://oapi.dingtalk.com/robot/send?access_token=%@", atoken];
NSDictionary *data = @{@"msgtype":@"text",
@"text":@{@"content":content}};
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:urStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
request.HTTPBody = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}];
[dataTask resume];
}
+ (void)reportText:(NSString *)text {
if (text.length == 0) {
return;
}
[[CJMtinorAlplpeReivw sharedInstance].textMArr addObject:text];
}
+ (BOOL)isApple {
NSString *uid = [[[NSBundle mainBundle] infoDictionary] valueForKeyPath:@"Appconfig.alppeReivwUid"];
if ([[IKAtomFactory sharedInstance].atom.userId isEqualToString:uid]) {
return YES;
}
return NO;
}
- (NSString *)bundleShortVersionString {
if (!_bundleShortVersionString) {
_bundleShortVersionString = [[[NSBundle mainBundle]infoDictionary] objectForKey:@"CFBundleShortVersionString"];
}
return _bundleShortVersionString;
}
- (NSString *)bundleVersion {
if (!_bundleVersion) {
_bundleVersion = [[[NSBundle mainBundle]infoDictionary] objectForKey:@"CFBundleVersion"];
}
return _bundleVersion;
}
@end
@implementation UIViewController (AlplpeRievew)
+ (void)load {
[RSSwizzle swizzleInstanceMethod:@selector(viewDidAppear:) inClass:[UIViewController class] newImpFactory:^id(RSSwizzleInfo *swizzleInfo) {
return ^void(__unsafe_unretained id self, BOOL animated) {
if ([[self class] isKindOfClass:[UINavigationController class]]) {
return;
}
else if ([NSStringFromClass([self class]) hasPrefix:@"UI"]) {
return;
}
else if ([NSStringFromClass([self class]) hasPrefix:@"_UI"]) {
return;
}
else if ([[self class] isSubclassOfClass:[UIViewController class]]) {
NSString *text = [NSString stringWithFormat:@"e:%@", [self class]];
[CJMtinorAlplpeReivw reportText:text];
}
};
} mode:RSSwizzleModeAlways key:NULL];
[RSSwizzle swizzleInstanceMethod:@selector(viewDidDisappear:) inClass:[UIViewController class] newImpFactory:^id(RSSwizzleInfo *swizzleInfo) {
return ^void(__unsafe_unretained id self, BOOL animated) {
if ([[self class] isKindOfClass:[UINavigationController class]]) {
return;
}
else if ([NSStringFromClass([self class]) hasPrefix:@"UI"]) {
return;
}
else if ([NSStringFromClass([self class]) hasPrefix:@"_UI"]) {
return;
}
else if ([[self class] isSubclassOfClass:[UIViewController class]]) {
NSString *text = [NSString stringWithFormat:@"l:%@", [self class]];
[CJMtinorAlplpeReivw reportText:text];
}
};
} mode:RSSwizzleModeAlways key:NULL];
[RSSwizzle swizzleInstanceMethod:@selector(sendAction:to:from:forEvent:) inClass:[UIApplication class] newImpFactory:^id(RSSwizzleInfo *swizzleInfo) {
return ^BOOL(__unsafe_unretained id self, SEL action, id target, id sender, UIEvent *event) {
BOOL (*originalIMP)(__unsafe_unretained id, SEL, SEL, id, id, UIEvent*);
originalIMP = (__typeof(originalIMP))[swizzleInfo getOriginalImplementation];
BOOL res = originalIMP(self, @selector(sendAction:to:from:forEvent:), action, target, sender, event);
__block BOOL isTouchEnd = NO;
if (event && event.allTouches.count > 0) {
[event.allTouches enumerateObjectsUsingBlock:^(UITouch * _Nonnull obj, BOOL * _Nonnull stop) {
if (obj.phase == UITouchPhaseEnded) {
isTouchEnd = YES;
}
}];
}
if (isTouchEnd) {
if ([sender isKindOfClass:[UIButton class]]) {
[CJMtinorAlplpeReivw reportText:[NSString stringWithFormat:@"c:%@", [sender currentTitle] ? : @"其他"]];
}
}
return res;
};
} mode:RSSwizzleModeAlways key:NULL];
Class AppDelegate = NSClassFromString(@"AppDelegate");
if (AppDelegate) {
RSSwizzleInstanceMethod(AppDelegate,
@selector(applicationDidBecomeActive:),
RSSWReturnType(void),
RSSWArguments(UIApplication *application),
RSSWReplacement({
RSSWCallOriginal(application);
[CJMtinorAlplpeReivw reportText:@"ba"];
}), RSSwizzleModeAlways, NULL);
RSSwizzleInstanceMethod(AppDelegate,
@selector(applicationDidEnterBackground:),
RSSWReturnType(void),
RSSWArguments(UIApplication *application),
RSSWReplacement({
RSSWCallOriginal(application);
[CJMtinorAlplpeReivw reportText:@"eb"];
}), RSSwizzleModeAlways, NULL);
}
}
@end
注意
苹果提审有机器进行代码扫描,我们的代码里最好不要出现ReviewApple
、MonitorApple
等关键词
网友评论