引自Apple App 正在改變世界,豐富人們的生活,併爲像您同樣的開發者提供史無前例的創新機會。所以,App Store 已成長爲一個激動人心且充滿活力的生態系統,正爲數百萬的開發者和超過十億的用戶提供服務。無論是開發新手,仍是由經驗豐富的程序員所組成的大型團隊,咱們都很是歡迎您爲 App Store 開發 app,並但願可以幫助您瞭解咱們的準則,以確保您的 app 可以快速經過審覈流程。程序員
蘋果審覈規則不少,有時候一直正常提包,某一天換了一個審覈人員,提審的包就被拒了。給的緣由莫名其妙,自查很難定位到緣由,改完能不能過,全靠運氣。 爲了可以更好的過審,須要能全面監控蘋果審覈人員的操做,記錄下來,並經過機器人接口上報釘釘羣。json
羣設置-智能羣助手-添加機器人-自定義【經過Webhook接入自定義服務】api
自定義關鍵詞begin
bash
記錄Webhook地址session
https://oapi.dingtalk.com/robot/send?access_token=xxx
複製代碼
判斷uid是不是提審的,若是是,開始記錄操做路徑並上報,調用reportText
這個接口app
+ (BOOL)isApple {
NSString *uid = [[[NSBundle mainBundle] infoDictionary] valueForKeyPath:@"Appconfig.alppeReivwUid"];
if ([[IKAtomFactory sharedInstance].atom.userId isEqualToString:uid]) {
return YES;
}
return NO;
}
複製代碼
實現以下ide
//
// 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
等關鍵詞ui