钱柜

攻略详情

教你在App Store 内查看应用的运营状况

2020-04-08 11:40:01

如果你关心 app 的运营状况,可能会使用类似于 App Annie 或是 ASO100 一类的工具,这类服务提供了一个网站,你可以在网站上搜索应用然后查看他们的详细信息,类似于实时排行、ASO 状况等等。

在经过一点研究之后,我发现这个东西完全可以直接在 App Store 内部完成,效果见下图:

 

 

App Store 的应用详情界面点击分享,弹出分享面板后点击 ASO100,可以直接弹出 Action Extension 并展示在 ASO100 里面的详细状况:

 

 

这样你看到任何喜欢的 App 都能直接在 App Store 内部查看运营状况,而且极大的好处是,Safari View Controller 可以和 Safari 共享 Cookie,这样登录态这些东西完全不用担心。

 

这里有个演示视频:视频

 

声明:本文以 ASO100 为例子,虽然我觉得 ASO100 做的确实不错,但本文实非广告,之后也会顺带介绍 App Annie 的方案。

 

# 如何写一个 Action Extension

 

这一部分直接略过,请参考 App Extension Programming Guide,另外我之前也写过一篇关于 Action Extension 的文章,感兴趣的可以看看:知乎专栏

 

# App Store 获得短链接

 

App Store 的详情页在弹出 Action Extension 的时候,会把很多信息带给 Action Extension,其中就包括 URL,我们可以在 viewDidLoad 里面拿到他,例如:

 

void(^loadCompletionHandler)(NSURL *, NSError *) = ^(NSURL *original, NSError *error) {

 

};

 

NSString *identifier = (NSString *)kUTTypeURL;

for (NSExtensionItem *item in self.extensionContext.inputItems) {

    for (NSItemProvider *itemProvider in item.attachments) {

        if ([itemProvider hasItemConformingToTypeIdentifier:identifier]) {

            [itemProvider loadItemForTypeIdentifier:identifier options:nil completionHandler:loadCompletionHandler];

            return;

        }

    }

}

我们会得到一个类似于 https://appsto.re/cn/gt799.i 的链接,这是一个 App Store 的短链,是没有办法直接使用它的。

 

# 获得包含 app identifier 的原始 URL

 

上面得到的 URL 只是一个短链,里面并不包含我们需要的 app id 信息,所以我们要的得到它。这个地方最容易想到的方案就是用一个 HTTP GET 把它给拉下来,Response 里面的 URL 就是 Redirect 之后的 URL。所以我尝试了一把:

 

[[[NSURLSession sharedSession] dataTaskWithRequest:[NSURLRequest requestWithURL:original]

                                 completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

                                 }] resume];

我这样尝试之后发现并没有发生任何事情,这个请求会一直到超时都不会有响应。

 

我估计这个行为跟在 Safari 里面直接贴 App Store 短链是一样的,iOS 会尝试用 App Store 打开它,然后我们本身就在 App Store 里面,而且就在当前的 app 页面,所以这个行为没有任何的效果。那么我们就要想办法找出跳转后的 URL,这里通过 Chrome 的调试工具来做。

 

我们打开 Chrome 的开发者工具,然后清理掉之前那些记录,把短链粘贴进去回车,然后可以得到一堆请求的结果:

 

 

我们只用看第一个 gt799.i 这个请求,注意观察 Header 里面红框的部分:

 

 

这个时候我们已经知道了跳转其实是通过这样一个请求:

 

https://itunes.apple.com/WebObjects/MZStore.woa/wa/redirectToContent?path=

Path 这个参数,就是 https://appsto.re/cn/gt799.i 里面的后缀做一下 URL Encode,我们这个请求再跳一次,就能得到该 App Web 页面,这个页面是包含 app id 的:

 

NSString *path = [[original.absoluteString stringByReplacingOccurrencesOfString:@"https://appsto.re"

                                                                     withString:@""] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];

NSURL *url = [NSURL URLWithString:[@"https://itunes.apple.com/WebObjects/MZStore.woa/wa/redirectToContent?path=" stringByAppendingString:path]];

[[[NSURLSession sharedSession] dataTaskWithRequest:[NSURLRequest requestWithURL:url]                         completionHandler:downloadCompletionHandler] resume];

# 解析出 app identifier

 

上一步的结果是一个类似于

 

https://itunes.apple.com/cn/app/pin-jian-tie-ban-kuo-zhan/id1039643846?l=en&mt=8

的链接,我们要做的是把 id1039643846 里面的 1039643846 给拿出来,这个东西就是能标记一个 app 的全球唯一的 app id,这一部分用正则,没太多好说的:

 

NSString *storeUrl = response.URL.absoluteString;

NSRange searchedRange = NSMakeRange(0, [storeUrl length]);

NSString *pattern = @"[0-9]{5,}";

NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern

                                                                       options:0

                                                                         error:&error];

NSArray *matches = [regex matchesInString:storeUrl options:0 range:searchedRange];

for (NSTextCheckingResult *match in matches) {

    NSString *identifier = [storeUrl substringWithRange:[match range]];

}

# 呈现结果

 

已经有 app id 了,其实怎么展现都无所谓了,如果你打算把这个玩意儿做成一个 app,你完全可以靠这个 id 去你的数据库里面查一个结果,然后爱怎么展示怎么展示。不过我这里只是个人使用,而且仅针对 App Annie 或者 ASO100,所以我只需要一个 Safari View Controller 就可以了:

 

// appannie: https://www.appannie.com/apps/ios/app/identifier/details/

// aso100: https://aso100.com/app/baseinfo/appid/identifier

 

NSURL *url = [NSURL URLWithString:[@"https://aso100.com/app/baseinfo/appid/" stringByAppendingString:identifier]];

SFSafariViewController *controller = [[SFSafariViewController alloc] initWithURL:url];

controller.delegate = self;

[self addChildViewController:controller];

[self.view addSubview:controller.view];

[controller didMoveToParentViewController:self];

[controller.view mas_makeConstraints:^(MASConstraintMaker *make) {

    make.edges.equalTo(self.view);

}];

ASO100 拼接 URL 的规则是 https://aso100.com/app/baseinfo/appid/identifier,如果你希望使用 App Annie 的话,把上述链接改成

 image.png

https://www.appannie.com/apps/ios/app/identifier/details/

的拼接方式即可。

 

就是这样,把 Safari View Controller 通过 ChildViewController 的方式添加到 Action Extension 里面,最后实现 Safari View Controller 的代理方法,让其在 Safari 关闭的时候退出插件,完毕:

 

- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller {

    [self.extensionContext completeRequestReturningItems:self.extensionContext.inputItems completionHandler:nil];

}

image.png

完整的 demo 可以在 GitHub 找到,仅供参考。

前往赚钱