日期: 2021 年 7 月 30 日

iOS解决Launch Screen.storyboard启动画面黑屏

查看启动屏图片的名字
启动图名字不要包含Launch这样的字眼。

启动图片工程中位置
将启动图放在工程的根目录下,不要放在Assets.xcassets中。

启动图的格式
建议使用png,尽量不要使用jpg

查看工程中是否仍在使用LaunchImage
将工程中与LaunchImage有关的全部删掉,包括Assets.xcassets中。*好在检查下plist文件和build Settings。

%title插图%num

%title插图%num

修改图片名字
有时候把启动图去掉,或者添加新的启动图,显示出来的还是之前的图片。这可能是缓存导致的,将启动图的名字改一下就会正常。

需要Clean重新编译
Clean后重新编译应用,或者直接清空DerivedData文件夹再重新编译。

删除应用重启手机
修改启动图后,*好卸载重装应用,有时可能还需要重启手机,否则可能会因为缓存还显示旧图片。

iOS开发时如何使用 Launch Screen Storyboard

静态启动图片

启动图片是iOS加载App的时候系统响应的直观呈现。近几年,随着屏幕尺寸的增多,制作相应的静态图片就变成一件十分让人头疼的事。在下面,我列举了一些 启动图片的尺寸(尺寸包括状态条区域)。为了简洁,我省略了横屏的版本:

  • iPad 2 and iPad mini (@1x): 768 x 1024
  • iPad and iPad mini (retina @2x): 1536 x 2048
  • iPhone 4s (retina @2x) 640 x 960
  • iPhone 5 (@2x): 640 x 1136
  • iPhone 6 (@2x): 750 x 1334
  • iPhone 6 Plus (@3x): 1242 x 2208

好消息是,在Xcode 6 and iOS 8允许使用NIB或storyboard launch screen 文件。利用auto layout 和size classes的优势,一个单独的NIB或storyboard文件在runtime时可以自动的去创建启动图片集。这就意味着,你想在全屏模式下支持iPhone 6 和 iPhone 6 Plus的话就无需提供匹配的的启动图集或者如上面列举出现来的不同尺寸的静态图片

( 26-Dec-2014 更新: 一定要搞清楚,支持iPhone 6 and iPhone 6 Plus ,要求你提供启动图片集合,可以是静态启动图集(static launch images),也可以是启动图布局文件( launch screen file)).

使用启动图片文件

Xcode6在创建新工程时默认添加了一个LaunchScreen.xib文件。对一个已经存在的工程可以用Launch Screen 模板创建一个新的文件。(译者注:在Xcode7里,默认添加的是LaunchScreen.storyboard文件,笔者因此遇到过一个大坑LaunchImage和LaunchScreen.xib混用出现的坑)

%title插图%num

这一步将会在工程中添加一个NIB文件,你可以在初始化的启动屏上添加单个视图或者视图控制器。如果你有多个视图,那么你则需要放弃Launch Screen模板,应该添加一个storyboard。然后在target的工程设置里面指定启动图来源:

%title插图%num

2014-12-24-005.png

这一步将会把 键 Launch screen interface file base name
(UILaunchStoryboardName)加到应用的plist 文件中

%title插图%num

2014-12-24-003.png

接下来,你可以在Interface Builder对启动视图进行布局,使autolayout和size classes作为必选项,为不同的屏幕创建匹配的图片。Xcode模板提供的风格,只是对app的名称和所有权进行了布局,这并不是一个*理想的范例。在你添加自己的视图之前,或许你想删掉它们:

%title插图%num

2014-12-24-004.png

你可以在Xcode中预览storyboard,或者在模拟器和真机上进行测试。尽管启动屏的展示的时间很短,但是你会发现,如果在App delegate的application:didFinishLaunchingWithOptions:方法中添加断点是有用的

Launch Screen 的局限性

系统在启动app之前装载启动文件,在这个过程中可能对app包含的一些文件产生限制(一些限制可能迫使你回退到 使用静态图片集):

  • app还没装载完毕,一些视图的层级结构还不存在,系统不能调用app中任何自定义的视图控制器去启动代码。
  • 你仅仅能使用标准的UIKit类,所以你可以用UIView或者UIViewController,自定义的子类则不可以。如果你尝试着去设置子类,将会得到一个“配置无效”的错误。
  • 启动文件仅仅能够用基础的UIKit视图,像UIImageView 和UILabel,不能使用 UIWebView。
  • 如果你用了storyboard,你可以指定多个视图控制器,但是仍旧有一些限制。例如,你可以在navagation或者tab bar controller嵌入几个视图控制器,但是一些更复杂的类,像UISplitViewController 并不起作用 (至少现在如此).
  • 本地化(译者注:我理解的是自己创建的,而非采用模板)启动图布局文件目前看起来并没有什么不好的影响。也许,你采用的*基本的本地化启动图布局文件可能是不在启动图上显示文字。
  • 你不能为iPhone和iPad指定不同的启动文件。因为auto layout 和size classes的局限性,如果这些设备有着显著不同的界面,就会出现问题。

如果你正在ios7系统上进行开发,那么你仍旧需要包含 静态启动图集。你可以包含启动图布局文件静态启动图集。那么,运行ios8系统的iPhone6将会使用启动图布局文件,而运行ios7系统的设备则回退使用 静态启动图集

Split View Controllers

如果你的根视图控制器是SplitViewControllers,至少在iOS8.1系统,你并没有太多的选择。如果你将SplitViewControllers添加到launch screen storyboard,它不会被装载。由于在iOS8.1中SplitViewControllers复杂度的增加,我怀疑在后续版本中也不会被支持。

除了回退去使用 静态启动图集,唯一能够选择的方式看起来只有放弃 分屏使用。例如,考虑一下接下来使用SplitViewController的iPhone和ipad的启动屏。在iphone(宽度较窄)设备上,初始化的屏幕仅展示主视图控制器(一个嵌入在Navigation Controller里的tableview controller)

%title插图%num

2014-12-24-iphone.png

在ipad(常规宽度)设备上,初始化后的启动屏在分屏控制器里展示的master and detail view controllers

%title插图%num

2014-12-24-ipad.png

这是一种常见的启动方式,但是在这种情况下,没有好的方法使用启动图布局文件.我的建议,即我能得到的*接近的方式是忽略启动屏,用一个嵌套在navigation controller的view controller 作为启动屏

%title插图%num

2014-12-24-006.png

尽管这种方式远远没有达到完美的地步,但是在适配(除了ipad分屏)所有设备用户初始化界面 方面多多少少做了贡献。呈现给用户的静态启动图集虽然效果足够好,但是自己不得不做出判断。

Runtime Generation (added 28-Dec-2014)

尽管苹果文档中并没有清楚地说明,但需要的启动图片在runtime时被生成了。在WWDC 2014
Platform State of the Union上被简短的提到过。你可以通过App在真机或者模拟器上生成的文件夹证实。被特定设备需要的启动图被缓存在Library/Caches/LaunchImages。下面的截屏显示了iPad Air 2生成的启动图片

%title插图%num

 

IOS使用Launch Screen.storyboard制作广告启动界面

*近项目在做的广告sdk,刚好自己需要去了解这个实现启动图加载广告这个功能,大家应该都了解,之前Xcode 6是LaunchScreen.xib来当作启动视图,不过到了Xcode 7就变成了Launch Screen.storyboard,其实这两个没有多大的区别,以下我就采用Xcode 7提供的LaunchScreen.storyboard 来实现这个功能,现在把自己经验和代码分享出来。

主要思路

获取Launch Screen.storyboard

通过使用storyborardID去获取启动视图viewcontroller

获取启动viewController的视图view

之后把视图view添加到window中

*后就是新建一个图片贴在视图view中

做个定时触发处理

废话不多说啦,直接贴代码出来:

AppDelegate.m中的代码

//获取LaunchScreen.storyborad

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@”Launch Screen” bundle:nil];

//通过使用storyborardID去获取启动页viewcontroller

UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@”LaunchScreen”];

//获取viewController的视图

self.view = viewController.view;

//把视图添加到window

[self.window addSubview:self.view];

self.launchView = [[UIImageView alloc] initWithFrame:self.window.frame];

[self.launchView setImage:[UIImage imageNamed:@”launch.jpg”]];//这边图片可以做网络请求加载图片、视频动画或者其他自定义的引导页

[self.view addSubview:self.launchView];

//将图片视图推送到前面

[self.window bringSubviewToFront:self.launchView];

//设置3秒定时触发

[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(colseLaunchScreen) userInfo:nil repeats:NO];

– (void)colseLaunchScreen {

if (self.launchView) {

[self.launchView removeFromSuperview];

self.launchView = nil;

}

if (self.view) {

[self.view removeFromSuperview];

self.view = nil;

}

}

这边也可以结合LaunchImage使用,方式也是差不多,这边就不多讲了

注意有个坑已填平了:之前我用的xcode项目中General中Main Interface 启动项目初始化的主界面storyboard,用以上方法一直看不到加载的广告,后面使用在AppDelegate代码方式去加载storyboard,就可以加载出来了,目前不清楚这个是什么问题,待研究发现,如有发现朋友,方便留言告知下,谢啦(后面经过友友们的指出,发现如果不是用代码加载storyboard,那General->Main Interface->的main.storyboard加载会新建window,跟你之前传入的window不是同一个,这个之前的就被覆盖了,导致看不到广告效果,之后我修改了方案,把window改成用window中viewController中view这要就避免代码加载stroyboard了)

这里注意一下,上面这个使用storyboard启动适用ios8.0以上,但现在应用差不多都是ios7.0起,开发者为了方便适配,大多都采用launchImage启动,这种也可以使用storyboard去获取广告,完全没有问题,但在加载初始化广告肯定会消耗一点点时间这要就会出现短暂storyboard的默认页面,这个可以通过把获取rootview先隐藏,等加载完毕广告再显示出来!这要问题解决了!

如果先获取launchImage的图片可以采用Cherpak Evgeny 分享在stackflow上的一个直接读取NSBundle中的设置 即可获取当前适用的LaunchImage的办法,代码我也贴出来:

CGSize viewSize =self.window.bounds.size;

NSString *viewOrientation =@”Portrait”;//横屏请设置成 @”Landscape”

NSString *launchImage =nil;

NSArray *imagesDict = [[[NSBundle mainBundle] infoDictionary] valueForKey:@”UILaunchImages”];

for(NSDictionary* dict in imagesDict) {

CGSize imageSize =CGSizeFromString(dict[@”UILaunchImageSize”]);

if(CGSizeEqualToSize(imageSize, viewSize) && [viewOrientation isEqualToString:dict[@”UILaunchImageOrientation”]]) {

launchImage = dict[@”UILaunchImageName”];

}

}

UIImageView *launchView = [[UIImageView alloc] initWithImage:[UIImageimageNamed:launchImage]];

launchView.frame=self.window.bounds;

launchView.contentMode=UIViewContentModeScaleAspectFill;

[self.window addSubview:launchView];

[UIView animateWithDuration:2.0f delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState

animations:^{

launchView.alpha=0.0f;

launchView.layer.transform=CATransform3DScale(CATransform3DIdentity,1.2,1.2,1);

}

completion:^(BOOL finished) {

[launchView removeFromSuperview];

}];

iOS中GestureRecognizer的6大手势与代理方法详细使用

#import “ViewController.h”@interface ViewController ()@property (weak, nonatomic) IBOutlet UIImageView *imageView;

@end

@implementation ViewController

– (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.\

[self setUpPinch];

[self setUpRotation];

[self setUpPan];

}

#pragma mark – 手势代理方法

// 是否允许开始触发手势

//- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer

//{

//    return NO;

//}

// 是否允许同时支持多个手势,默认是不支持多个手势

// 返回yes表示支持多个手势

– (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer

{

return YES;

}

// 是否允许接收手指的触摸点

//- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{

//    // 获取当前的触摸点

//    CGPoint curP = [touch locationInView:self.imageView];

//

//    if (curP.x < self.imageView.bounds.size.width * 0.5) {

//        return NO;

//    }else{

//        return YES;

//    }

//}

1.#pragma mark – 点按手势

– (void)setUpTap

{

// 创建点按手势

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];

tap.delegate = self;

[_imageView addGestureRecognizer:tap];

}

– (void)tap:(UITapGestureRecognizer *)tap

{

NSLog(@”%s”,__func__);

}

2.#pragma mark – 长按手势

// 默认会触发两次

– (void)setUpLongPress

{

UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];

[self.imageView addGestureRecognizer:longPress];

}

– (void)longPress:(UILongPressGestureRecognizer *)longPress

{

if (longPress.state == UIGestureRecognizerStateBegan) {

NSLog(@”%s”,__func__);

}

}

3.#pragma mark – 清扫

– (void)setUpSwipe

{

// 默认轻扫的方向是往右

UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe)];

swipe.direction = UISwipeGestureRecognizerDirectionUp;

[self.imageView addGestureRecognizer:swipe];

// 如果以后想要一个控件支持多个方向的轻扫,必须创建多个轻扫手势,一个轻扫手势只支持一个方向

// 默认轻扫的方向是往右

UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe)];

swipeDown.direction = UISwipeGestureRecognizerDirectionDown;

[self.imageView addGestureRecognizer:swipeDown];

}

– (void)swipe

{

NSLog(@”%s”,__func__);

}

4.#pragma mark – 旋转手势

– (void)setUpRotation

{

UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotation:)];

rotation.delegate = self;

[self.imageView addGestureRecognizer:rotation];

}

// 默认传递的旋转的角度都是相对于*开始的位置

– (void)rotation:(UIRotationGestureRecognizer *)rotation

{

self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, rotation.rotation);

// 复位

rotation.rotation = 0;

// 获取手势旋转的角度

NSLog(@”%f”,rotation.rotation);

}

5.#pragma mark – 捏合

– (void)setUpPinch

{

UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)];

pinch.delegate = self;

[self.imageView addGestureRecognizer:pinch];

}

– (void)pinch:(UIPinchGestureRecognizer *)pinch

{

self.imageView.transform = CGAffineTransformScale(self.imageView.transform, pinch.scale, pinch.scale);

// 复位

pinch.scale = 1;

}

6.#pragma mark – 拖拽

– (void)setUpPan

{

UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];

[self.imageView addGestureRecognizer:pan];

}

– (void)pan:(UIPanGestureRecognizer *)pan

{

// 获取手势的触摸点

// CGPoint curP = [pan locationInView:self.imageView];

// 移动视图

// 获取手势的移动,也是相对于*开始的位置

CGPoint transP = [pan translationInView:self.imageView];

self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, transP.x, transP.y);

// 复位

[pan setTranslation:CGPointZero inView:self.imageView];

//  NSLog(@”%@”,NSStringFromCGPoint(curP));

}

有什么方法能够检测手机上已安装的 APP 中有哪些支持 fcm 的?

有什么方法能够检测手机上已安装的 APP 中有哪些支持 fcm 的?

 

*近一个月从 ios 换到 MIUI ( eu 版),这才发现原来 Android 党天天说推送比不过 iOS 并不是夸大其词。iOS 上通知虽然泛滥吧,但我可以主动忽略它,顶多碍眼一些罢了,可在国内用 Android 你就要担心通知是不是漏了? fcm 有没有 disconnected ?新安装的 APP 支不支持 fcm 亦或是 mipush ?需不需要打开自启动开关?所以装国内 APP 时也尽可能选择 play 版,可奈何 play 版也不一定就能走 fcm… 于是就问问大家有没有什么方便的办法能够知道一款 APP 是否接入 fcm 推送?

15 条回复    2021-07-11 10:50:07 +08:00

lzsqq754318010
    1

lzsqq754318010   22 天前

可能有人会说看 fcm 的 log,但问题是有些 App 你不知道它什么时候会有推送,而且频率也可能不是很高。
learningman
    2

learningman   22 天前 via Android

黑阈看得到
pakro888
    3

pakro888   22 天前

绿色守护也能看到
lzsqq754318010
    4

lzsqq754318010   22 天前

感谢上面二位,我去瞧瞧。
john6lq
    5

john6lq   22 天前 via iPhone

对不起,请问 FCM 是?
voiyy
    6

voiyy   22 天前   ❤️ 2

libchecker app
JensenQian
    7

JensenQian   22 天前 via Android

@john6lq https://firebase.google.com/docs/cloud-messaging
YvanGu
    8

YvanGu   22 天前

斑朵,可以看到支持的各种推送
dingwen07
    9

dingwen07   22 天前 via iPhone

在国内 FCM 确实不如 APN
国产 App 兼容 FCM 的很少,你就当没有吧,印象中通知有点用的也就个闲鱼和微信国际版是走 FCM 的。。。
国外 App 还是很好用的,基本上有通知需求都会走 FCM 。
dingwen07
    10

dingwen07   22 天前 via iPhone

我是用绿色守护看,国产 app 全部不给自启动,国外 app 操作系统默认允许自启动

 

terabithia
    11

terabithia   22 天前

@dingwen07 走 FCM 也还是要允许自启吧,只是禁止后台。我现在用的 play 上下载的微信和钉钉可以走 FCM,其他的好像也没啥有推送的需求……
dingwen07
    12

dingwen07   22 天前 via iPhone

@terabithia #11 允许自启动是必须的,禁止后台我就不清楚了,反正我用的三星上面允许自己和禁止后台是一起的

微信必须得是外国手机号注册的,不然不走 FCM,我主帐号是国内的就很难受


terabithia
    13

terabithia   22 天前

@dingwen07 我刚刚发现我把 twitter 禁止自启好像也有推送。我的微信是国内手机号码注册的,我把微信也设置为走代理,而且是全局,可以走 FCM 的,不过这个要看代理的网络质量,好在我对推送也不是那么敏感,随缘吧
janus77
    14

janus77   21 天前

这个你做不到完全准确的
我就说一句,推送是主动发起的,就算他在代码层面支持了推送,某些消息运营就是不想在 fcm 这个渠道里面发,你能怎么办?
0A0
    15

0A0   19 天前 via Android

eu 版的 fcm 是完整支持的。
剩下就是各个 app 自己的锅了。cn 版需要打开自启动,或者同时打开后台。eu 版正常不需要,只是有的 app 不按标准来,才需要你检查自启动,后台等额外的操作。
比如 line,不管 cn 和 eu,开启自启动后都能正常推送 fcm 信息,属于正常。只是不正常的 app 太多了而已。

如何在 x86 上编译安卓系统,使其支持安装 ARM 架构的 apk?

如何在 x86 上编译安卓系统,使其支持安装 ARM 架构的 apk,并且能够在 x86 上使用模拟器运行?

 

实验室有工作需要修改安卓系统,然后在上面跑从安卓市场爬下来的大批量应用。

编译的安卓系统不支持 ARM

现在存在的问题是,从安卓市场里爬下来的应用都是 ARM 架构的,在编译好的安卓系统里安装时会报错 使用的安卓源码版本是android-9.0.0_r36 编译命令为

export OUT_DIR_COMMON_BASE=/out
source ./build/envsetup.sh
lunch sdk_phone_x86-userdebug
make -j20

# 编译完成后运行模拟器
emulator

之后用 adb 安装某新闻应用com.ss.android.article.news_8.3.3.apk会报错

Failure [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113]

推测是 apk 用到了 arm 架构的二进制文件,没办法在 x86 架构上跑。在网上搜索了一下,发现 x86 好像也是能运行 arm 模拟器的,但是运行效率会很低。于是换了一个目标文件夹自己尝试了一下编译了一个新版本 ( lunch 使用*个默认选项 aosp_arm-eng )

make clobber
export OUT_DIR_COMMON_BASE=~/out-arm
source ./build/envsetup.sh
lunch aosp_arm-eng
make -j20

# 编译完成后运行模拟器
emulator

但是此时模拟器长时间黑屏,无法启动。不清楚是什么原因

Android Studio 中的系统映像支持 ARM

之后搜索了一下,发现在 Android 文档中提到了运行 ARM 的方法

Android 9 和 11 系统映像对 ARM 二进制文件的支持

如果您之前因为应用依赖 ARM 二进制文件而无法使用 Android 模拟器,那么现在您可以使用 Android 9 x86 系统映像或任何 Android 11 系统映像来运行应用,而无需再下载特定的系统映像来运行 ARM 二进制文件。这些 Android 9 和 Android 11 系统映像默认支持 ARM,而且与采用完全 ARM 模拟的系统映像相比,它们提供显著提升的性能。

做了以下尝试:

  1. 从 Android Studio 里获取的 Android9 和 Android11 系统映像都能进行com.ss.android.article.news_8.3.3.apk的安装。(说明从 AS 获取的系统映像支持 ARM 架构的 apk )
  2. 同时也试了一下 Android Studio 中 ARM 的模拟器( Pixel2 XL,android7.1.1 armv7 ),能运行起来,但是确实非常卡顿。这时使用 adb 安装com.ss.android.article.news_8.3.3.apk无法得到响应(输入命令后长时间内命令行无反馈)。对于低版本的 x86 模拟器的模拟器( Pixel2 XL,android7.1.1 x86 ),则会报错Failure [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113](架构错误会报错,但架构正确也不一定能安装)

现在我的主要问题是以下两个:

  1. 是否一定能确认安装失败的原因是架构问题?
  2. 应该用什么配置编译安卓,使得 x86 的系统映像支持 arm ?或者是我缺失了什么文件吗?

谢谢各位

24 条回复    2021-07-21 17:18:21 +08:00

winterbells
    1

winterbells   14 天前

没看懂,大部分的安卓应用不都是四种架构都有吗( x86 x8664 arm arm64-va8 )

去 apkmirror 下?

strawberrydafu
    2

strawberrydafu   14 天前

@winterbells 研究是要对国内应用进行检测。检测的环境需要通过修改安卓系统来进行构建(获取部分库的调用信息)。因此需要跑的是国内的应用,但很多国内应用都没办法在 apkmirror 里找到。
目前来说*方便的方法就是从部分应用商店的网页爬,这时没办法选择架构,默认下载下来的版本就是对应 arm 架构的。如果能下载到 x86 架构的应用,这个问题也能绕过去。(我试着联系过几家国内的应用商店,不过都石沉大海了
vk42
    3

vk42   14 天前

基本无解,找老板要钱买个性能好点的电脑吧……
nicocho
    4

nicocho   14 天前

现在 Android 应用开发给 Apk 瘦身, *条就是条件允许的前提下,只保留 ARM-V7 之类动态库。
因为市面上 X86 的 Android 设备市场占有率基本可以忽略。
0o0O0o0O0o
    5

0o0O0o0O0o   14 天前 via iPhone

因为就是不支持,常用模拟器已经一些*少数的 x86 设备靠的是 libhoudini,Google 在较新版本的 android studio 的 emulator 里也提供了类似方案以适配高版本的 Android

https://github.com/geeks-r-us/anbox-playstore-installer

https://android-developers.googleblog.com/2020/03/run-arm-apps-on-android-emulator.html?m=1

trgl
    6

trgl   14 天前

退而求其次,弄个树莓派?
nieyujiang
    7

nieyujiang   14 天前

现在市面上还有 x86 的安卓手机么……
tomato1111
    8

tomato1111   14 天前 via Android

arm 转 x86 的安卓虚拟机效率*底。。。你那个黑屏很有可能只是系统还在启动。。。不是开玩笑。。。。 安卓官方这些模拟器,尤其是转译的没有任何实用价值。。。建议还是用第三方游戏模拟器的,比如 mumu,夜神,蓝叠之类的,他们兼容 arm 而且效率也可以
aneostart173
    9

aneostart173   14 天前

qemu 模拟 arm 啊。
NSAgold
    10

NSAgold   14 天前

houdini 二进制转换库
当初 intel 的 atom 平板用的这个来运行 arm 的应用

ch2
    11

ch2   14 天前

用 houdini 就行了,x86 转译 arm 效果还是不错的,只是有的 app 会检测架构是不是 x86,不是 arm 就不提供正常功能
imcczy
    12

imcczy   14 天前

1. 就是架构的问题
2. 这个情况太多,别人根本没法帮你下结论

此外,别信什么 houdini 什么的,此项目 Intel 早就不做了,多年未更新,你要大批量跑 App 必然会遇到 bug 。但*近 Google 官方貌似出了一个类似的,可以试试
其实你这个场景,华为的 ARM 服务器非常适合,支持 qemu+aosp7/9 或者 anbox,原生 arm 支持。48 核 916 或者 96 核 920 任君选

ReferenceE
    13

ReferenceE   14 天前 via Android

好家伙,你就是微软员工负责 win11 安卓子系统的是吧
0o0O0o0O0o
    14

0o0O0o0O0o   14 天前 via iPhone

@imcczy #12

houdini 是市面模拟器主流方案吧? bug 虽然有,但我觉得目前是比 Google 那个 arm translation 好太多了,缺点只是 Android 版本低。

我的体验是:

arm 的云手机(也包括你说的自己跑 qemu+aosp )才是真的难搞,那些做黑产的专项优化的云手机我不清楚,但我个人能买到的或者 github 能找到的此类方案,大部分适配真的成问题。比如 aws 上的 genymotion cloud arm,闪退率惊人,没有仔细研究,看日志大概都是有些东西没模拟全,还不如它的 x86 版本+libhoudini 。。。

而 anbox 的主要优势我觉得在于 lxc 和开源,论兼容(此处兼容和传统意义上的兼容有些不一样,要包括反检测)和商业模拟器是没法比的,它也不在意这一点,跑楼主的需求,会需要写大量的反检测。

https://www.genymotion.com/blog/just-launched-arm-native-android-in-the-cloud-environment-on-aws/

0o0O0o0O0o
    15

0o0O0o0O0o   14 天前 via iPhone

@imcczy
@0o0O0o0O0o #14

其实我也知道 arm+kvm 是上限很高的方案,x86 转译太容易被检测,只是我目前没有找到很成熟的方案或者产品,如果是我接触的局限,你可以推荐一下,我一直很向往云手机。。。

imcczy
    16

imcczy   14 天前

@0o0O0o0O0o #14

官方 emulator 就是 qemu 呀

成熟商用方案目前是没有的,尤其是有特殊需求的,得自己做。华为一直说要对外商用。
华为这套基础软硬件我们用着还行,当然前后做了很多定制的优化,以及外围服务等。
供参考: https://support.huaweicloud.com/kunpengcps/kunpengcps.html
PS:我也见过把几十块 rk3399 板集成在一起的” 服务器”…

strawberrydafu
    17

strawberrydafu   14 天前

谢谢各位回复。
我*开始是比较想知道如何编译出 android studio 中提供的镜像( android9 & 11 兼容 arm ),不过看起来 houdini 和 anbox 也满足需求,我这两天先尝试一下。
项目需要修改密码学库代码( JCE & JCA ),还不太清楚 Anbox 是否能够容易地进行相应修改
strawberrydafu
    18

strawberrydafu   14 天前

另外服务器相关的方案不太清楚开销是否能承受(项目要跑大量应用),直觉上讲优先级可能比较低
3dwelcome
    19

3dwelcome   13 天前

国内的 PC 模拟器基本上都是 houdini 技术,又不可能自己来写 arm -> x86 转译器。
ryh
    20

ryh   13 天前

买个 arm64 的 chromebook 来测试? 必须使用 x86 吗?
BrokenVns
    21

BrokenVns   13 天前

能申请经费的话,2000-3000 买块 Android 推荐的开发版( https://source.android.google.cn/setup/build/devices )或者弄台 M1(*快的 Android 模拟器)。源码编译的话我觉得可以考虑使用 cuttlefish 替代 QEMU,我自己的体验来说 cuttlefish 版比 qemu 版快一些。https://source.android.google.cn/setup/create/cuttlefish
MiketsuSmasher
    22

MiketsuSmasher   13 天前

如果只是调试,可以考虑用 BlissOS-x86,*新版本的安卓 9 镜像支持*大多数 arm 应用,虽然不知道他们的 houdini 是从哪里来的
Rheinmetal
    23

Rheinmetal   13 天前

小黄鱼捡工作室淘汰手机 然后刷机 这个方案省事一点 吧
zhanlanhuizhang
    24

zhanlanhuizhang   9 天前

你直接买个小米手机,刷个自己编译的系统。不然使用虚拟机就只有 x86,x86_64 。现在好像没有看懂 arm 的虚拟机。

Jetpack Compose 1.0 发布了,移动端与桌面端分别体验如何?

24 条回复    2021-07-30 15:16:10 +08:00

3dwelcome
    1

3dwelcome   1 天前

教育机构狂喜,新技术代表新的培训项目,又能收割一批新的小白学员了。

开发者嘛,管你性能好不好,现在要开发都用三端统一的 UI 解决方案( web,android,ios),单独为安卓开发,又费钱又浪费时间,过了几年,发现自己是用爱给 Google 团队发电。

以前 XML 还能丢给美术,设计一下 UI 界面美感。现在 Compose 这种纯代码声明 UI,找哪个设计师帮你写设计代码?又不是人人都是技术美术,普通理科码农手写 UI 代码,巨丑。

nicocho
    2

nicocho   23 小时 32 分钟前

上午刚准备了解下 jetpack , 一篇文章给出的数据如下

构建时间能够 减少 29%
XML 行数大幅减少了 76%
APK 大小缩减了 41%
方法数减少了 17%

Cloud9527
    3

Cloud9527   23 小时 17 分钟前

@3dwelcome 基本没有培训 Android 的了。。。我认识一些开发还没用这个
meteor957
    4

meteor957   22 小时 32 分钟前

早几年估计是个大新闻,现在 Android 开发快要灭*的情况下,除了卖课的感觉都没啥人关注
pocarisweat
    5

pocarisweat   22 小时 6 分钟前

就算是 Java 也比 Electron 看着顺眼啊,哎
fescover
    6

fescover   21 小时 51 分钟前

哪天支持 ios 就学
tanranran
    7

tanranran   19 小时 25 分钟前

基于 canvas 的,性能上会比 xml 好一些,个人猜测,后期会和 flutter 大融合?
aabbcc112233
    8

aabbcc112233   19 小时 21 分钟前 via Android   ❤️ 1

@3dwelcome 请问哪个公司 xml 给 UI 来写????
Michelangelono
    9

Michelangelono   19 小时 17 分钟前

@nicocho apk 体积如何做到的减少?毕竟 jetpack 实际是增加了很多依赖。
coolmint
    10

coolmint   19 小时 6 分钟前 via iPhone

我在 rc1 的时候把 compose 引入到项目中来,简单重写了一个界面,感觉还是不错的,当然和纯用 compose 构建的项目还是区别比较大的,以后准备用 compose 做更多的页面进一步深度体验
3dwelcome
    11

3dwelcome   18 小时 59 分钟前 via Android

@aabbcc112233 xml 有可视化编辑器,UI 设计师来改个颜色,弄个字体大小和样式总没问题吧。
compose 可就全部都是代码了。
aabbcc112233
    12

aabbcc112233   18 小时 50 分钟前   ❤️ 2

@3dwelcome 没听说过 UI 有这个能力,也没听说过哪个公司让 UI 参与 xml 布局
Yadomin
    13

Yadomin   18 小时 46 分钟前

别的不说,用 Jetpack Compose 重写的 Idea Toolbox 已经烂了
Yadomin
    14

Yadomin   18 小时 46 分钟前

内存占用比肩 Electron
maninfog
    15

maninfog   18 小时 42 分钟前 via iPhone

体验还是不错的,将数据驱动 UI 的思想贯彻到了*致,声明式 UI 有一种用了回不去的感觉。

首先底层还是基于 Skia,还是 canvas 那一套,所以和 view 的互操作性很高,可以渐近的接入。Dialog 看了下底层还是原生的包了下。

*开始担心没有实时 preview 写起来不习惯,后面发现渐渐习惯了也还好,也会尝试着写完一个页面再调试,不再依赖预览。

如果你的设计是 MD,用 Compose 会很舒服,内置丰富的 MD 控件; Compose 处理换肤也是轻而易举,想想使用 view 时,一些换肤框架还要去 hook LayoutInflater 有点头皮发麻…

至于坑的话,个人觉得就是刚出来,还没有状态管理的*佳实践,另外就是页面组织不好的话阅读起来有点困难。

3dwelcome
    16

3dwelcome   18 小时 5 分钟前

@aabbcc112233 XML 是数据描述,是可以和内部工作流一些可视化工具桥接的。*终给 UI 展示的,就是普通 low code 设计软件操作界面。

但是 Compose 的组件都是偏手写代码,很难和工具整合。界面也代码和逻辑都混在一起,不好分离。对 UI 来说,改一点点,都异常困难。

国内的需求本来就是改的多,只有很少团队是完全按照设计稿一次成型的。

MakHoCheung
    17

MakHoCheung   18 小时 1 分钟前

@Yadomin 这个不同,compose for desktop 底层还是 基于 Swing,而且还是 alpha 阶段,不急
0bit
    18

0bit   17 小时 58 分钟前

按照折腾 SwiftUI 的教训,尽量还是多等等吧
3dwelcome
    19

3dwelcome   17 小时 30 分钟前

@maninfog “想想使用 view 时,一些换肤框架还要去 hook LayoutInflater 有点头皮发麻”

google 用 xml 的初衷应该是为了界面灵活多变,然而为了性能,*后弄了个谁都看不懂的二进制 XML 格式,还和资源强关联,想改都改不了。活生生把开发者的一些道路给堵死。

如果 LayoutInflater 用的全部都是明文 XML,也不至于沦落到今天这个尴尬的下场。

sunbreak
    20

sunbreak   9 小时 49 分钟前

@MakHoCheung 不是基于 Swing,是基于 https://github.com/JetBrains/skija/

但确实保持了和 Swing 、JavaFx 框架的互操作性: https://blog.jetbrains.com/cross-post/jetpack-compose-for-desktop-milestone-2-released/

MakHoCheung
    21

MakHoCheung   8 小时 18 分钟前

@sunbreak 我知道它是用 skija 渲染,但是你点进去看 window,还是 swing 的 window 。
ingramyang
    22

ingramyang   8 小时 7 分钟前 via Android

没有用,就是 flutter 的复制品。但是 flutter 可以做到一套 UI 代码多平台运行,可 compose 的桌面和移动端 UI 接口都不一样,所以没啥用这东西。
wobuhuicode
    23

wobuhuicode   7 小时 40 分钟前

用了 5 年 react-native 都没有一个正式版……
james2013
    24

james2013   2 小时 11 分钟前

个人觉得这个功能很垃圾,xml 能够很好的分离逻辑和界面,这个功能又把界面和逻辑搞在 java 里,复制的界面 xml 布局几百行,甚至要分几个 xml 导入,方便管理

实用!五款新型 Linux 命令行工具

在Linux/Unix系统的日常使用中,我们需要使用很多命令行工具来完成工作,以及理解和管理我们的系统,例如使用du来监视磁盘利用率、top来显示系统资源。有些工具已经有很长的历史了。例如,top于1984年首次发布,而du的首次问世可追溯至1971年。

多年来,这些工具已经过现代化的改造,并移植到了不同的系统中,但总的来说,它们仍然保留了*初的想法、外观和感觉。

这些工具都非常优秀,对于许多系统管理员的工作流程来说都是必不可少的。但近年来,开源社区开发了不少更具优势的替代工具。虽然有些工具华而不实,但有些则大大提高了实用性,成为了现代系统的*佳选择。 在本文中,我将介绍五种标准Linux命令行工具的替代品。

%title插图%num

du的替代:ncdu

 

NCurses磁盘使用率(NCurses DiskUsage,即ncdu)工具提供了与du类似的结果,但其基于curses的交互式界面可以显示消耗了大部分磁盘空间的目录。

首先Ncdu需要花一些时间分析磁盘,然后按照*常用的顺序显示目录或文件,如下所示:

  1. ncdu 1.14.2 ~ Use the arrow keys to navigate, press ? for help
  2. — /home/rgerardi ————————————————————
  3.    96.7 GiB [##########] /libvirt
  4.    33.9 GiB [###       ] /.crc
  5.     7.0 GiB [          ] /Projects
  6. .   4.7 GiB [          ] /Downloads
  7. .   3.9 GiB [          ] /.local
  8.     2.5 GiB [          ] /.minishift
  9.     2.4 GiB [          ] /.vagrant.d
  10. .   1.9 GiB [          ] /.config
  11. .   1.8 GiB [          ] /.cache
  12.     1.7 GiB [          ] /Videos
  13.     1.1 GiB [          ] /go
  14.   692.6 MiB [          ] /Documents
  15. 591.5 MiB [          ] /tmp
  16.   139.2 MiB [          ] /.var
  17.   104.4 MiB [          ] /.oh-my-zsh
  18.    82.0 MiB [          ] /scripts
  19.    55.8 MiB [          ] /.mozilla
  20.    54.6 MiB [          ] /.kube
  21.    41.8 MiB [          ] /.vim
  22.    31.5 MiB [          ] /.ansible
  23.    31.3 MiB [          ] /.gem
  24.    26.5 MiB [          ] /.VIM_UNDO_FILES
  25.    15.3 MiB [          ] /Personal
  26.     2.6 MiB [          ]  .ansible_module_generated
  27.     1.4 MiB [          ] /backgrounds
  28.   944.0 KiB [          ] /Pictures
  29.   644.0 KiB [          ]  .zsh_history
  30.   536.0 KiB [          ] /.ansible_async
  31.  Total disk usage: 159.4 GiB  Apparent size: 280.8 GiB  Items: 561540

你可以通过方向键导航到每个结果。如果在选中的结果上按下Enter,则ncdu将显示该目录的内容:

  1. — /home/rgerardi/libvirt —————————————————-
  2.                          /..
  3.    91.3 GiB [##########] /images
  4.     5.3 GiB [          ] /media

你可以深入各个目录,找出哪些文件占用的磁盘空间*多。使用左方向键可以返回到上一个目录。在默认情况下,你可以按d键删除文件,但在删除文件之前ncdu会要求确认。如果你想禁止删除操作以防止发生意外,则可以通过-r选项设置只读访问:ncdu -r。

ncdu可用于许多平台和Linux发行版。例如,你可以使用dnf从官方代码库直接将其安装在Fedora上:

$ sudo dnf install ncdu

更多有关该工具的信息,请参见:https://dev.yorhel.nl/ncdu。

%title插图%num

top的替代:htop

 

htop是一个类似于top的交互式进程浏览器,提供了更好的用户体验。在默认情况下,htop显示的各项指标与top相同,而且是漂亮的彩色。

默认的htop如下所示:

%title插图%num

与默认的top相比:

%title插图%num

此外,htop的顶部还提供了系统的概述信息,底部的命令栏则显示了功能键命令,你还可以按下F2进入设置页面来自定义界面。在设置页面中,你可以更改其颜色,添加或删除指标、更改概述栏的显示选项。

虽然top的*新版本也可以通过配置获得相似的结果,但htop提供的默认配置更为合理,作为一个进程浏览器更加易于使用。

如果想了解有关该项目的更多信息,请查看htop主页(https://hisham.hm/htop/)。

%title插图%num

man的替代:tldr

 

tldr命令行工具显示可以简化的命令文档,而且大部分文档都提供示例。它是tldr pages项目(https://tldr.sh/)的客户端。

这个工具不是man的替代品。man pages仍然是许多工具的规范以及完整的信息源。但是,在某些情况下,man的内容太多了。有时,你不需要有关命令的所有信息。你只需要记住基本选项。例如,curl命令的man page几乎有3,000行。相比之下,curl的tldr只有40行,如下所示:

  1. $ tldr curl
  2. # curl
  3.   Transfers data from or to a server.
  4.   Supports most protocols, including HTTP, FTP, and POP3.
  5.   More information: <https://curl.haxx.se>.
  6. – Download the contents of an URL to a file:
  7.   curl http://example.com -o filename
  8. – Download a file, saving the output under the filename indicated by the URL:
  9.   curl -O http://example.com/filename
  10. – Download a file, following [L]ocation redirects, and automatically [C]ontinuing (resuming) a previous file transfer:
  11.   curl -O -L -C – http://example.com/filename
  12. – Send form-encoded data (POST request of type `application/x-www-form-urlencoded`):
  13.   curl -d ‘name=bob’ http://example.com/form                                                                                            
  14. – Send a request with an extra header, using a custom HTTP method:
  15.   curl -H ‘X-My-Header: 123’ -X PUT http://example.com                                                                                  
  16. – Send data in JSON format, specifying the appropriate content-type header:
  17.   curl -d ‘{“name”:”bob”}’ -H ‘Content-Type: application/json’ http://example.com/users/1234
  18. … TRUNCATED OUTPUT

TLDR的全称是“too long; didn’tread”(太长;未读),这是一句网络流行语,表示文章太长。这个名字非常适合这个汇总工具,因为manpages虽然非常实用,但内容太长。

在Fedora中,tldr客户端是用Python编写的。你可以使用dnf安装。有关其他客户端选项,请参见tldr pages项目(https://tldr.sh/)。

通常,tldr工具需要访问互联网才能查询tldr页面。Fedora中的Python客户端允许你下载和缓存这些页面以供离线访问。

有关tldr的更多信息,请运行tldr tldr。

%title插图%num

用sed/grep查找JSON数据的替代:jq

 

jq是JSON的命令行处理器。就像sed或grep一样,但主要是为了处理JSON数据。如果你是日常任务需要使用JSON的开发人员或系统管理员,那么这是你的工具箱中必不可少的工具。

与通用文本处理工具(例如grep和sed)相比,jq的主要优点在于它了解JSON数据结构,你可以通过一个表达式创建复杂的查询。

举例说明,假设你正在尝试在下列JSON文件中查找容器的名称:

  1. {
  2.   “apiVersion”“v1”,
  3.   “kind”“Pod”,
  4.   “metadata”: {
  5.     “labels”: {
  6.       “app”“myapp”
  7.     },
  8.     “name”“myapp”,
  9.     “namespace”“project1”
  10.   },
  11.   “spec”: {
  12.     “containers”: [
  13.       {
  14.         “command”: [
  15.           “sleep”,
  16.           “3000”
  17.         ],
  18.         “image”“busybox”,
  19.         “imagePullPolicy”“IfNotPresent”,
  20.         “name”“busybox”
  21.       },
  22.       {
  23.         “name”“nginx”,
  24.         “image”“nginx”,
  25.         “resources”: {},
  26.         “imagePullPolicy”“IfNotPresent”
  27.       }
  28.     ],
  29.     “restartPolicy”“Never”
  30.   }
  31. }

如果你利用grep直接查询name,则结果为:

  1. $ grep name k8s-pod.json
  2.         “name”“myapp”,
  3.         “namespace”“project1”
  4.                 “name”“busybox”
  5.                 “name”“nginx”,

grep会返回所有包含单词name的行。你可以在grep中添加一些其他选项来限制查询结果,并通过正则表达式操作找到容器的名称。在使用jq获得所需结果时,你只需要使用一个模拟向下导航数据结构的表达式,如下所示:

  1. $ jq ‘.spec.containers[].name’ k8s-pod.json
  2. “busybox”
  3. “nginx”

该命令会返回两个容器的名称。如果你只想查看第二个容器的名称,则可以在表达式中添加数组元素索引:

  1. $ jq ‘.spec.containers[1].name’ k8s-pod.json
  2. “nginx”

因为jq能够理解数据结构,所以即使文件格式稍有变化,它也可以提供相同的结果。但对于grep和se来说,格式稍有变化提供的结果就会完全不同。

jq还有很多功能,我需要用另写一篇文章才能介绍其所有的功能。有关更多信息,请参见jq项目页面(https://stedolan.github.io/jq/)、manpages或tldr jq。

%title插图%num

find的替代:fd

 

fd是find命令的一种简单快速的替代。它的目的不是替换find的功能,而是提供一些合理的默认值,在某些情况下非常有用。

例如,在包含Git代码库的目录中搜索源代码文件时,fd会自动排除隐藏的文件和目录(包括.git目录),并忽略.gitignore文件中的模式。通常,它可以更快地查询,并提供相关度更高的结果。

在默认情况下,fd会针对当前目录执行不区分大小写的模式搜索,并输出彩色的结果。使用find进行的相同搜索时,你需要提供其他命令行参数。例如,搜索当前目录中所有的markdown文件(即.md或.MD文件),find命令如下所示:

$ find . -iname "*.md"$ find . -iname "*.md"

而如下fd搜索能够返回相同的结果:

$ fd .md

在有些情况下,fd也需要其他选项。例如,如果想让搜索包括隐藏的文件和目录,则必须使用选项-H,而find则不需要。

fd可用于许多Linux发行版。在Fedora中安装fd可使用标准代码库:

$ sudo dnf install fd-find

有关更多信息,请请见fd的GitHub代码库(https://github.com/sharkdp/fd/)。

%title插图%num

优秀的替代工具与久经考验的实用程序

 

尽管我还是习惯使用旧工具,尤其是在远程连接到服务器时,但新的替代工具提供了额外的好处,而且在许多情况下都很有帮助性。特别是帮助我在Linux台式机和笔记本电脑上管理和工作。

你是否使用其他工具来处理工作流程?请在下方留言。

原文:https://opensource.com/article/20/6/modern-linux-command-line-tools

Android adb 客户端是如何检测到自定义服务端端口的?

adb 客户端能自动发现局域网中的 adb 服务端,当我手机开启 wireless adb 后,总能收到局域网内其他客户端发出的连接请求,开始以为是通过探测默认端口 5555 实现的,但我把服务端端口改成其他后,仍然能收到连接请求,不知道这是如何实现的,难道是服务端主动向局域网内广播自己的配置?

7 条回复    2021-07-30 12:35:01 +08:00

learningman
    1

learningman   1 天前

我知道有个叫 SSDP 的协议,估计是差不多的东西吧
yukiww233
    2

yukiww233   1 天前

问下局域网内其他人(adb client)是怎么发送请求连接的呗
没准人家写了个工具遍历局域网内端口
wjploop
    3

wjploop   1 天前

有趣的问题

我也认为不是服务端自己广播自己的配置,手机不该浪费自己电量来做这事,而是客户端主动探测出来的。

客户端如何探测?

使用 nmap 工具查询当前局域网活跃的主机以及开放的端口 /服务,我下载玩了会,当手机开放无线 adbd 时确实可以检测到,且手机开放的端口很少,根据手机开放端口很少这点,客户端只要尝试连接就行了。

不知道现实中你指的客户端是谁,可能是公司的测试人员?由于 IP 动态分配的原因连上了你手机?

jim9606
    4

jim9606   1 天前   ❤️ 3

Android 的 adbd 激活无线调试后会通过 mDNS 发布一个_adb-tls-connect._tcp 服务。
adb v30 开始设置环境变量 ADB_MDNS_OPENSCREEN=1 后,adb devices 会利用 mDNS 自动发现设备。
andyskaura
    5

andyskaura   1 天前

@jim9606 感谢 涨姿势了 通过 mdns 发现设备
MLawliet
    6

MLawliet   23 小时 31 分钟前

@wjploop 目前发现是局域网中跑着 Android studio 、Unity 这类工具的设备会主动向开启无线的 adbd 发起连接请求,这些设备上肯定没有人为跑检测程序

@jim9606 非常感谢,*次知道 mDNS…

xingstar
    7

xingstar   4 小时 36 分钟前

真是学习了,感谢(⊙o⊙)…

aabbcc112233
    8

aabbcc112233   1 天前

@MLawliet AS 怎么能够向已开启无限调试的设备发起连接呢?没看到入口
MLawliet
    9

MLawliet   4 小时 22 分钟前

@aabbcc112233 自动的啊,AS 会自动执行 adb devices 命令查找局域网内开启调试的设备然后连接
友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速