当前位置: 首页 > news >正文

工厂做哪个网站好网站的关键词在哪里设置

工厂做哪个网站好,网站的关键词在哪里设置,网站做百度推广的要求,wordpress 维护中摘要#xff1a; 如果 app 连续 crash 两次无法启动#xff0c;用户往往会选择卸载。本文介绍如何该类 crash 的自修复技术。 点此查看原文#xff1a;http://click.aliyun.com/m/41487/ 作者#xff1a;阿里云-移动云-大前端团队 前言 如果 app 连续 crash 两次无法启动…摘要 如果 app 连续 crash 两次无法启动用户往往会选择卸载。本文介绍如何该类 crash 的自修复技术。 点此查看原文http://click.aliyun.com/m/41487/ 作者阿里云-移动云-大前端团队 前言 如果 app 连续 crash 两次无法启动用户往往会选择卸载。 连续启动 crash 应该是 crash 类型中最严重的一类该问题常常与数据库操作有关比如数据库损坏、服务端返回数据错误存入数据库app 读取时产生数组越界、找不到方法。 那么除了热修复能否“自修复”该问题呢 在微信读书团队发布的《iOS 启动连续闪退保护方案》 一文中给出了连续启动crash的自修复技术的思路讲解并在GitHub上给出了技术实现并开源了 GYBootingProtection。方案思路很好很轻量级。 实现原理 在微信读书团队给出的文章中已经有比较详细的阐述在此不做赘述实现的流程图如下所示但有个实现上可以优化下可以降低50%以上误报机率监听用户手动划掉 APP 这个事件其中一些特定场景是可以获取的。另外在这里也给出对其 API 设计的建议。最后给出优化后的实现。 优化降低50%以上误报机率 用户主动 kill 掉 APP 分为两种情况 App在前台时用户手动划掉APP的时候 APP在后台时划掉APP 第一种场景更为常见可以通过监听 UIApplicationWillTerminateNotification 来捕获该动作捕获后恢复计数。第二种情况无法监听到。但也足以降低 50% 以上的误报机率。 对原有API设计的几点优化意见 1. 机制状态应当用枚举来做为API透出 该机制当前所处的状态比如NeedFix 、isFixing建议用枚举来做为API透出。比如 APP 启动正常 正在检测是否会在特定时间内是否会 Crash注意检测状态下“连续启动崩溃计数”个数小于或等于上限值 APP 出现连续启动 Crash需要采取修复措施 APP 出现连续启动 Crash正在修复中 2. 关键数值应当做为初始化参数供用户设置 当前启动Crash的状态 达到需要执行上报操作的“连续启动崩溃计数”个数。 达到需要执行修复操作的“连续启动崩溃计数”个数。 APP 启动后经过多少秒可以将“连续启动崩溃计数”清零 3. 修复、上报逻辑应当支持用户异步操作 reportBlock 上报逻辑 repairtBlock 修复逻辑 比如 typedef void (^BoolCompletionHandler)(BOOL succeeded, NSError *error); typedef void (^RepairBlock)(ABSBoolCompletionHandler completionHandler); 用户执行 BoolCompletionHandler 后即可知道是否执行完毕并且支持异步操作。 异步操作带来的问题可以通过前面提到的枚举API来实时监测状态来决定各种其他操作。 什么时候会出现该异常 连续启动 crash 自修复技术实现与原理解析 下面给出优化后的代码实现 // // CYLBootingProtection.h // // // Created by ChenYilong on 18/01/10. // Copyright © 2018年 ChenYilong. All rights reserved. //#import Foundation/Foundation.htypedef void (^ABSBoolCompletionHandler)(BOOL succeeded, NSError *error); typedef void (^ABSRepairBlock)(ABSBoolCompletionHandler completionHandler); typedef void (^ABSReportBlock)(NSUInteger crashCounts);typedef NS_ENUM(NSInteger, BootingProtectionStatus) {BootingProtectionStatusNormal, /** APP 启动正常 */BootingProtectionStatusNormalChecking, /** 正在检测是否会在特定时间内是否会 Crash注意检测状态下“连续启动崩溃计数”个数小于或等于上限值 */BootingProtectionStatusNeedFix, /** APP 出现连续启动 Crash需要采取修复措施 */BootingProtectionStatusFixing, /** APP 出现连续启动 Crash正在修复中... */ };/** * 启动连续 crash 保护。 * 启动后 _crashOnLaunchTimeIntervalThreshold 秒内 crash反复超过 _continuousCrashOnLaunchNeedToReport 次则上报日志超过 _continuousCrashOnLaunchNeedToFix 则启动修复操作。 */ interface CYLBootingProtection : NSObject/** * 启动连续 crash 保护方法。 * 前置条件在 App 启动时注册 crash 处理函数在 crash 时调用[CYLBootingProtection addCrashCountIfNeeded]。 * 启动后一定时间内crashOnLaunchTimeIntervalThreshold秒内crash反复超过一定次数continuousCrashOnLaunchNeedToReport次则上报日志超过一定次数continuousCrashOnLaunchNeedToFix次则启动修复程序在一定时间内crashOnLaunchTimeIntervalThreshold秒 秒后若没有 crash 将“连续启动崩溃计数”计数置零。reportBlock 上报逻辑repairtBlock 修复逻辑完成后执行 [self setCrashCount:0]*/ - (void)launchContinuousCrashProtect;/*! * 当前启动Crash的状态 */ property (nonatomic, assign, readonly) BootingProtectionStatus bootingProtectionStatus;/*! * 达到需要执行上报操作的“连续启动崩溃计数”个数。 */ property (nonatomic, assign, readonly) NSUInteger continuousCrashOnLaunchNeedToReport;/*! * 达到需要执行修复操作的“连续启动崩溃计数”个数。 */ property (nonatomic, assign, readonly) NSUInteger continuousCrashOnLaunchNeedToFix;/*! * APP 启动后经过多少秒可以将“连续启动崩溃计数”清零 */ property (nonatomic, assign, readonly) NSTimeInterval crashOnLaunchTimeIntervalThreshold;/*! * 借助 context 可以让多个模块注册事件并且事件 block 能独立执行互不干扰。 */ property (nonatomic, copy, readonly) NSString *context;/*! * details 启动后kCrashOnLaunchTimeIntervalThreshold秒内crash反复超过continuousCrashOnLaunchNeedToReport次则上报日志超过continuousCrashOnLaunchNeedToFix则启动修复程序当所有操作完成后执行 completion。在 crashOnLaunchTimeIntervalThreshold 秒后若没有 crash 将 kContinuousCrashOnLaunchCounterKey 计数置零。 * param context 借助 context 可以让多个模块注册事件并且事件 block 能独立执行互不干扰。 */ - (instancetype)initWithContinuousCrashOnLaunchNeedToReport:(NSUInteger)continuousCrashOnLaunchNeedToReportcontinuousCrashOnLaunchNeedToFix:(NSUInteger)continuousCrashOnLaunchNeedToFixcrashOnLaunchTimeIntervalThreshold:(NSTimeInterval)crashOnLaunchTimeIntervalThresholdcontext:(NSString *)context; /*! * 当前“连续启动崩溃“的状态 */(BootingProtectionStatus)bootingProtectionStatusWithContext:(NSString *)context continuousCrashOnLaunchNeedToFix:(NSUInteger)continuousCrashOnLaunchNeedToFix;/*! * 设置上报逻辑参数 crashCounts 为启动连续 crash 次数 */ - (void)setReportBlock:(ABSReportBlock)reportBlock;/*! * 设置修复逻辑 */ - (void)setRepairBlock:(ABSRepairBlock)repairtBlock; (void)setLogger:(void (^)(NSString *))logger;end // // CYLBootingProtection.m // // // Created by ChenYilong on 18/01/10. // Copyright © 2018年 ChenYilong. All rights reserved. //#import CYLBootingProtection.h #import UIKit/UIKit.hstatic dispatch_queue_t _exceptionOperationQueue 0; void (^Logger)(NSString *log);interface CYLBootingProtection ()property (nonatomic, assign) NSUInteger continuousCrashOnLaunchNeedToReport; property (nonatomic, assign) NSUInteger continuousCrashOnLaunchNeedToFix; property (nonatomic, assign) NSTimeInterval crashOnLaunchTimeIntervalThreshold; property (nonatomic, copy) NSString *context; property (nonatomic, copy) ABSReportBlock reportBlock; property (nonatomic, copy) ABSRepairBlock repairBlock;/*! * 设置“连续启动崩溃计数”个数 */ - (void)setCrashCount:(NSInteger)count;/*! * 设置“连续启动崩溃计数”个数 */(void)setCrashCount:(NSUInteger)count context:(NSString *)context;/*! * “连续启动崩溃计数”个数 */ - (NSUInteger)crashCount;/*! * “连续启动崩溃计数”个数 */(NSUInteger)crashCountWithContext:(NSString *)context;endimplementation CYLBootingProtection(void)initialize {static dispatch_once_t onceToken;dispatch_once(onceToken, ^{_exceptionOperationQueue dispatch_queue_create(com.ChenYilong.CYLBootingProtection.fileCacheQueue, DISPATCH_QUEUE_SERIAL);}); } - (instancetype)initWithContinuousCrashOnLaunchNeedToReport:(NSUInteger)continuousCrashOnLaunchNeedToReportcontinuousCrashOnLaunchNeedToFix:(NSUInteger)continuousCrashOnLaunchNeedToFixcrashOnLaunchTimeIntervalThreshold:(NSTimeInterval)crashOnLaunchTimeIntervalThresholdcontext:(NSString *)context {if (!(self [super init])) {return nil;}_continuousCrashOnLaunchNeedToReport continuousCrashOnLaunchNeedToReport;_continuousCrashOnLaunchNeedToFix continuousCrashOnLaunchNeedToFix;_crashOnLaunchTimeIntervalThreshold crashOnLaunchTimeIntervalThreshold;_context [context copy];[[NSNotificationCenter defaultCenter] addObserver:selfselector:selector(applicationWillTerminate:)name:UIApplicationWillTerminateNotificationobject:[UIApplication sharedApplication]];return self; }/*! * App在前台时用户手动划掉APP的时候不计入检测。 * 但是APP在后台时划掉APP无法检测出来。 * 见https://stackoverflow.com/a/35041565/3395008 */ - (void)applicationWillTerminate:(NSNotification *)note {BOOL isNormalChecking [self isNormalChecking];if (isNormalChecking) {[self decreaseCrashCount];} }- (void)dealloc {[[NSNotificationCenter defaultCenter] removeObserver:self]; }/* 支持同步修复、异步修复两种修复方式 - 异步修复不卡顿主UI但有修复未完成就被再次触发crash、或者用户kill掉的可能。需要用户手动根据修复状态来选择性地进行操作应该有回掉。 - 同步修复最简单直观在主线程删除或者下载修复包。 */ - (void)launchContinuousCrashProtect {NSAssert(_repairBlock, _repairBlock is nil!);[[self class] Logger:CYLBootingProtection: Launch continuous crash report];[self resetBootingProtectionStatus];NSUInteger launchCrashes [self crashCount];// 上报if (launchCrashes self.continuousCrashOnLaunchNeedToReport) {NSString *logString [NSString stringWithFormat:CYLBootingProtection: App has continuously crashed for % times. Now synchronize uploading crash report and begin fixing procedure., (launchCrashes)];[[self class] Logger:logString];if (_reportBlock) {dispatch_async(dispatch_get_main_queue(),^{_reportBlock(launchCrashes);});}}// 修复if ([self isUpToBootingProtectionCount]) {[[self class] Logger:need to repair];[self setIsFixing:YES];if (_repairBlock) {ABSBoolCompletionHandler completionHandler ^(BOOL succeeded, NSError *__nullable error){if (succeeded) {[self resetCrashCount];} else {[[self class] Logger:error.description];}};dispatch_async(dispatch_get_main_queue(),^{_repairBlock(completionHandler);});}} else {[self increaseCrashCount:launchCrashes];// 正常流程无需修复[[self class] Logger:need no repair];// 记录启动时刻用于计算启动连续 crash// 重置启动 crash 计数dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.crashOnLaunchTimeIntervalThreshold * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void){// APP活过了阈值时间重置崩溃计数NSString *logString [NSString stringWithFormat:CYLBootingProtection: long live the app ( more than % seconds ), now reset crash counts, (self.crashOnLaunchTimeIntervalThreshold)];[[self class] Logger:logString];[self resetCrashCount];});} }//减少计数的时机用户手动划掉APP - (void)decreaseCrashCount {NSUInteger oldCrashCount [self crashCount];[self decreaseCrashCountWithOldCrashCount:oldCrashCount]; }- (void)decreaseCrashCountWithOldCrashCount:(NSUInteger)oldCrashCount {dispatch_sync(_exceptionOperationQueue, ^{if (oldCrashCount 0) {[self setCrashCount:oldCrashCount-1];}[self resetBootingProtectionStatus];}); }//重制计数的时机修复完成、或者用户手动划掉APP - (void)resetCrashCount {[self setCrashCount:0];[self resetBootingProtectionStatus]; }//只在未达到计数上限时才会增加计数 - (void)increaseCrashCount:(NSUInteger)oldCrashCount {dispatch_sync(_exceptionOperationQueue, ^{[self setIsNormalChecking:YES];[self setCrashCount:oldCrashCount1];}); }- (void)resetBootingProtectionStatus {[self setIsNormalChecking:NO];[self setIsFixing:NO]; }- (BootingProtectionStatus)bootingProtectionStatus {return [[self class] bootingProtectionStatusWithContext:_context continuousCrashOnLaunchNeedToFix:_continuousCrashOnLaunchNeedToFix]; }/*! * attention 注意之所以要检查 BootingProtectionStatusNormalChecking 原因如下-launchContinuousCrashProtect 方法与 -bootingProtectionStatus 方法如果 -launchContinuousCrashProtect 先执行那么会造成如下问题 假设n为上限但crashn-1次但是用 -bootingProtectionStatus 判断出来当前已经处于n次了。原因如下crashn-1次正常流程计数1变成n次 随后在检查 -bootingProtectionStatus 时发现已经处于异常状态了实际是正常状态。所以需要使用BootingProtectionStatusNormalChecking 来进行区分。 */(BootingProtectionStatus)bootingProtectionStatusWithContext:(NSString *)context continuousCrashOnLaunchNeedToFix:(NSUInteger)continuousCrashOnLaunchNeedToFix {BOOL isNormalChecking [self isNormalCheckingWithContext:context];if (isNormalChecking) {return BootingProtectionStatusNormalChecking;}BOOL isUpToBootingProtectionCount [self isUpToBootingProtectionCountWithContext:contextcontinuousCrashOnLaunchNeedToFix:continuousCrashOnLaunchNeedToFix];if (!isUpToBootingProtectionCount) {return BootingProtectionStatusNormal;}BootingProtectionStatus type;BOOL isFixingCrash [self isFixingCrashWithContext:context];if (isFixingCrash) {type BootingProtectionStatusFixing;} else {type BootingProtectionStatusNeedFix;}return type; }- (NSUInteger)crashCount {return [[self class] crashCountWithContext:_context]; }- (void)setCrashCount:(NSInteger)count {if (count 0) {[[self class] setCrashCount:count context:_context];} }- (void)setIsFixing:(BOOL)isFixingCrash {[[self class] setIsFixing:isFixingCrash context:_context]; }/*! * 是否正在修复 */ - (BOOL)isFixingCrash {return [[self class] isFixingCrashWithContext:_context]; }- (void)setIsNormalChecking:(BOOL)isNormalChecking {[[self class] setIsNormalChecking:isNormalChecking context:_context]; }/*! * 是否正在检查 */ - (BOOL)isNormalChecking {return [[self class] isNormalCheckingWithContext:_context]; } (NSUInteger)crashCountWithContext:(NSString *)context {NSString *continuousCrashOnLaunchCounterKey [self continuousCrashOnLaunchCounterKeyWithContext:context];NSUInteger crashCount [[NSUserDefaults standardUserDefaults] integerForKey:continuousCrashOnLaunchCounterKey];NSString *logString [NSString stringWithFormat:crashCount:%, (crashCount)];[[self class] Logger:logString];return crashCount; } (void)setCrashCount:(NSUInteger)count context:(NSString *)context {NSString *continuousCrashOnLaunchCounterKey [self continuousCrashOnLaunchCounterKeyWithContext:context];NSString *logString [NSString stringWithFormat:setCrashCount:%, (count)];[[self class] Logger:logString];NSUserDefaults *defaults [NSUserDefaults standardUserDefaults];[defaults setInteger:count forKey:continuousCrashOnLaunchCounterKey];[defaults synchronize]; } (void)setIsFixing:(BOOL)isFixingCrash context:(NSString *)context {NSString *continuousCrashFixingKey [[self class] continuousCrashFixingKeyWithContext:context];NSString *logString [NSString stringWithFormat:setisFixingCrash:{%}, (isFixingCrash)];[[self class] Logger:logString];NSUserDefaults *defaults [NSUserDefaults standardUserDefaults];[defaults setBool:isFixingCrash forKey:continuousCrashFixingKey];[defaults synchronize]; } (BOOL)isFixingCrashWithContext:(NSString *)context {NSString *continuousCrashFixingKey [[self class] continuousCrashFixingKeyWithContext:context];BOOL isFixingCrash [[NSUserDefaults standardUserDefaults] boolForKey:continuousCrashFixingKey];NSString *logString [NSString stringWithFormat:isFixingCrash:%, (isFixingCrash)];[[self class] Logger:logString];return isFixingCrash; } (void)setIsNormalChecking:(BOOL)isNormalChecking context:(NSString *)context {NSString *continuousCrashNormalCheckingKey [[self class] continuousCrashNormalCheckingKeyWithContext:context];NSString *logString [NSString stringWithFormat:setIsNormalChecking:{%}, (isNormalChecking)];[[self class] Logger:logString];NSUserDefaults *defaults [NSUserDefaults standardUserDefaults];[defaults setBool:isNormalChecking forKey:continuousCrashNormalCheckingKey];[defaults synchronize]; } (BOOL)isNormalCheckingWithContext:(NSString *)context {NSString *continuousCrashFixingKey [[self class] continuousCrashNormalCheckingKeyWithContext:context];BOOL isFixingCrash [[NSUserDefaults standardUserDefaults] boolForKey:continuousCrashFixingKey];NSString *logString [NSString stringWithFormat:isIsNormalChecking:%, (isFixingCrash)];[[self class] Logger:logString];return isFixingCrash; }- (BOOL)isUpToBootingProtectionCount {return [[self class] isUpToBootingProtectionCountWithContext:_context continuousCrashOnLaunchNeedToFix:_continuousCrashOnLaunchNeedToFix]; } (BOOL)isUpToBootingProtectionCountWithContext:(NSString *)context continuousCrashOnLaunchNeedToFix:(NSUInteger)continuousCrashOnLaunchNeedToFix {BOOL isUpToCount [self crashCountWithContext:context] continuousCrashOnLaunchNeedToFix;if (isUpToCount) {return YES;}return NO; }- (void)setReportBlock:(ABSReportBlock)block {_reportBlock block; }- (void)setRepairBlock:(ABSRepairBlock)block {_repairBlock block; }/*! * “连续启动崩溃计数”个数对应的Key * 默认为 _CONTINUOUS_CRASH_COUNTER_KEY */(NSString *)continuousCrashOnLaunchCounterKeyWithContext:(NSString *)context {BOOL isValid [[self class] isValidString:context];NSString *validContext isValid ? context : ;NSString *continuousCrashOnLaunchCounterKey [NSString stringWithFormat:%_CONTINUOUS_CRASH_COUNTER_KEY, validContext];return continuousCrashOnLaunchCounterKey; }/*! * 是否正在修复记录对应的Key * 默认为 _CONTINUOUS_CRASH_FIXING_KEY */(NSString *)continuousCrashFixingKeyWithContext:(NSString *)context {BOOL isValid [[self class] isValidString:context];NSString *validContext isValid ? context : ;NSString *continuousCrashFixingKey [NSString stringWithFormat:%_CONTINUOUS_CRASH_FIXING_KEY, validContext];return continuousCrashFixingKey; }/*! * 是否正在检查是否在特定时间内会Crash对应的Key * 默认为 _CONTINUOUS_CRASH_CHECKING_KEY */(NSString *)continuousCrashNormalCheckingKeyWithContext:(NSString *)context {BOOL isValid [[self class] isValidString:context];NSString *validContext isValid ? context : ;NSString *continuousCrashFixingKey [NSString stringWithFormat:%_CONTINUOUS_CRASH_CHECKING_KEY, validContext];return continuousCrashFixingKey; }#pragma mark - #pragma mark - log and util Methods (void)setLogger:(void (^)(NSString *))logger {Logger [logger copy]; } (void)Logger:(NSString *)log {if (Logger) Logger(log); } (BOOL)isValidString:(id)notValidString {if (!notValidString) {return NO;}if (![notValidString isKindOfClass:[NSString class]]) {return NO;}NSInteger stringLength 0;try {stringLength [notValidString length];} catch (NSException *exception) {}if (stringLength 0) {return NO;}return YES; }end 下面是相应的验证步骤 等待15秒会有对应计数清零的操作日志输出 2018-01-18 16:25:37.1629800800 BootingProtection[89773:15553277] 类名与方法名-[AppDelegate onBeforeBootingProtection]_block_invoke在第45行描述CYLBootingProtection: Launch continuous crash report 2018-01-18 16:25:37.1631400800 BootingProtection[89773:15553277] 类名与方法名-[AppDelegate onBeforeBootingProtection]_block_invoke在第45行描述setIsNormalChecking:{0} 2018-01-18 16:25:37.1657380800 BootingProtection[89773:15553277] 类名与方法名-[AppDelegate onBeforeBootingProtection]_block_invoke在第45行描述setisFixingCrash:{0} 2018-01-18 16:25:37.1668830800 BootingProtection[89773:15553277] 类名与方法名-[AppDelegate onBeforeBootingProtection]_block_invoke在第45行描述crashCount:0 2018-01-18 16:25:37.1671020800 BootingProtection[89773:15553277] 类名与方法名-[AppDelegate onBeforeBootingProtection]_block_invoke在第45行描述crashCount:0 2018-01-18 16:25:37.1672530800 BootingProtection[89773:15553277] 类名与方法名-[AppDelegate onBeforeBootingProtection]_block_invoke在第45行描述setIsNormalChecking:{1} 2018-01-18 16:25:37.1679380800 BootingProtection[89773:15553277] 类名与方法名-[AppDelegate onBeforeBootingProtection]_block_invoke在第45行描述setCrashCount:1 2018-01-18 16:25:37.1688060800 BootingProtection[89773:15553277] 类名与方法名-[AppDelegate onBeforeBootingProtection]_block_invoke在第45行描述need no repair2018-01-18 16:25:52.2251970800 BootingProtection[89773:15553277] 类名与方法名-[AppDelegate onBeforeBootingProtection]_block_invoke在第45行描述CYLBootingProtection: long live the app ( more than 15 seconds ), now reset crash counts 2018-01-18 16:25:52.2253780800 BootingProtection[89773:15553277] 类名与方法名-[AppDelegate onBeforeBootingProtection]_block_invoke在第45行描述setCrashCount:0 2018-01-18 16:25:52.2262340800 BootingProtection[89773:15553277] 类名与方法名-[AppDelegate onBeforeBootingProtection]_block_invoke在第45行描述setIsNormalChecking:{0} 2018-01-18 16:25:52.2265950800 BootingProtection[89773:15553277] 类名与方法名-[AppDelegate onBeforeBootingProtection]_block_invoke在第45行描述setisFixingCrash:{0}
http://www.yutouwan.com/news/168218/

相关文章:

  • 电商设计网站有哪些在线购物网站 模版
  • 汽车网站建设参考文献开题报告百度地图广告投放
  • seo网站推广目的图片常采用gif或jpeg格式
  • 深圳微商城网站设计多少钱微信公众号网页怎么制作
  • 宁波拾谷网站建设毕业设计 建设网站
  • 律师网站建设品牌wordpress -editor
  • 建设一个下载网站网站怎做
  • 丽江古城区建设局网站注册规划师报考条件2022
  • 济南做设计公司网站佛山企业网站建设公司
  • 网站的通知栏一般用什么控件做深圳公交公司官网
  • 浙江网站建设公司电话网站策划书撰写流程
  • 官方网站建设费用php能做手机网站吗
  • 河北省住房和城乡建设厅新网站做视频资源网站
  • 自助建站系统代理重庆公司章程电子版在哪里下载
  • 浦江网站建设yw126电商设计招聘
  • 苏州定制网站建设宣传类的网站有哪些
  • 佛山网站建设公司哪家好这么做国外网站的国内镜像站
  • 免费的网站登录模板下载如何查看网站模板
  • 主题资源网站制作平台开发者模式关掉好还是开着好
  • 国外做行程的网站wordpress手机不能看视频
  • 如何在公司网站下设置邮箱丹阳网站建设要多少钱
  • 网站竞价什么是网络营销中的免费营销策略
  • 舟山网站设计公司网站顶部展出的大幅广告
  • rails网站开发东莞网站设计哪家强
  • 做食品网站的素材网站备案填写
  • 推荐广东中山网站建设国际网站建设的目的
  • 网站建设合伙合同范本wordpress固定链接发布失败
  • 个人如何申请网站电商怎么做才能赚钱
  • 在putty做网站要拷贝什么中国搜索引擎排行榜
  • 内蒙古自治区工程建设网站成立公司合作协议书范本