XMPPManager 解析

来源:http://www.cnblogs.com/lurenq/archive/2017/06/16/7026283.html
-Advertisement-
Play Games

一、用戶登錄流程 用戶登錄流程.png 註意:XMPP核心文件,基於TCP的XML流的傳輸,XMPPFrame框架是通過代理的方式實現消息傳遞的 實現用戶登錄的步驟如下: 1、實例化XMPPStream並設置代理,同時添加代理到工作隊列 2、使用JID連接至伺服器,預設埠為5222,JID字元串中 ...


一、用戶登錄流程


用戶登錄流程.png
  • 註意:XMPP核心文件,基於TCP的XML流的傳輸,XMPPFrame框架是通過代理的方式實現消息傳遞的

實現用戶登錄的步驟如下:

  • 1、實例化XMPPStream並設置代理,同時添加代理到工作隊列
  • 2、使用JID連接至伺服器,預設埠為5222,JID字元串中需要包含伺服器的功能變數名稱
  • 3、 在完成連接的代理方法中驗證用戶密碼,連接完成後XMPPStream的isConnect屬性為YES
    +4、 在驗證代理方法中判斷用戶是否登錄成功
  • 5、上線或者下線成功後,向伺服器發送Presence數據,以更新用戶在伺服器的狀態

二、註意

  • 為了簡化開發,XMPP的引用程式通常會將XMPPStream放置在AppDelegate中,以便於全局訪問

三、分析

1、封裝登錄工具類 JPLoginTool

  • 利用工具類,保存用戶登錄信息到沙盒中
    1. 頭文件 .h
#import <Foundation/Foundation.h>

@interface JPLoginTool : NSObject

/**
 *  保存登錄信息到沙盒
 */
+(void)saveLoginInfoWithAccount:(NSString *)account pwd:(NSString *)pwd domain:(NSString *)domain;

/**
 *  獲取沙盒的帳號
 *
 */
+(NSString *)account;

/**
 *  獲取沙盒的密碼
 *
 */
+(NSString *)password;


/**
 *  獲取沙盒的功能變數名稱
 *
 */
+(NSString *)domain;

/**
 *  從沙盒清除所有的用戶登錄信息
 */
+(void)removeAllLoginInfo;

/**
 *  獲取用戶登錄狀態
 *
 */
+(BOOL)isLogin;


/**
 *  設置用戶登錄狀態
 */
+(void)setLogin:(BOOL)login;
@end
    1. .m實現文件
#import "JPLoginTool.h"

#define kAccountKey @"account"
#define kPasswordKey @"passsword"
#define kDomainKey @"domain"
#define kIsLoginKey @"isLogin"


@implementation JPLoginTool

+(void)saveLoginInfoWithAccount:(NSString *)account pwd:(NSString *)pwd domain:(NSString *)domain{
    NSUserDefaults *defaults =  [NSUserDefaults standardUserDefaults];
    [defaults setObject:account forKey:kAccountKey];
    [defaults setObject:pwd forKey:kPasswordKey];
    [defaults setObject:domain forKey:kDomainKey];

    //同步沙盒
    [defaults synchronize];
}

/**
 *  獲取沙盒的帳號
 *
 */
+(NSString *)account{

    return [[NSUserDefaults standardUserDefaults] objectForKey:kAccountKey];
}

/**
 *  獲取沙盒的密碼
 *
 */
+(NSString *)password{
    return [[NSUserDefaults standardUserDefaults] objectForKey:kPasswordKey];
}

/**
 *  獲取沙盒的功能變數名稱
 *
 */
+(NSString *)domain{
    return [[NSUserDefaults standardUserDefaults] objectForKey:kDomainKey];
}

/**
 *  從沙盒清除所有的用戶登錄信息
 *
 */
+(void)removeAllLoginInfo{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults removeObjectForKey:kAccountKey];
    [defaults removeObjectForKey:kPasswordKey];
    [defaults removeObjectForKey:kDomainKey];
    [defaults synchronize];
}


/**
 *  獲取用戶登錄狀態
 *
 */
+(BOOL)isLogin{
    return [[NSUserDefaults standardUserDefaults] boolForKey:kIsLoginKey];
}


/**
 *  設置用戶登錄狀態
 */
+(void)setLogin:(BOOL)login{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setBool:login forKey:kIsLoginKey];
    [defaults synchronize];
}
@end

2、AppDelegate.h 文件中

  • 1、首先,我們佈局登錄界面,提供登錄按鈕,當我們點擊登錄按鈕時就進行登錄操作,因為XMPPFrame的相關操作都建議寫在AppDelegate文件中,所以我們需要在AppDelegate.h文件中提供介面給用戶,而至於那些連接到伺服器以及授權等操作都寫在AppDelegate.m中不用暴露給用戶。

    #pragma mark 用戶登錄
    -(void)xmppUserLogin;
  • 2、但是,當我們點擊登錄,在控制器的登錄方法中,拿到應用程式的代理,然後調用應用代理的xmppUserLogin方法,此時不僅要執行登錄操作,而且應用代理必須要告訴我們是否登錄成功,因為登錄操作是封裝到AppDelegate中的 - > 這就要實現兩者之間的通信了。
    • 有多種通信方式,通知/代理/block/action等,這裡我選擇代理,所以重新設置應用代理提供的登錄介面為:
// 在應用代理頭文件中

// 1. 定義block

typedef enum {
    XMPPResultTypeLogining,//正在登錄中
    XMPPResultTypeLoginSuccess,//登錄成功
    XMPPResultTypeLoginFailure,//登錄失敗
    XMPPResultTypeNetError,//網路不給力
    XMPPResultTypeUnknowDomain,//功能變數名稱不存在
    XMPPResultTypeConnectionRefused//伺服器拒絕連接
} XMPPResultType;

typedef void (^XMPPResultBlock)(XMPPResultType resultType);//xmpp請求結果的block

// 2.提供為外界登錄介面
#pragma mark 用戶登錄
-(void)xmppUserLogin:(XMPPResultBlock)resultBlock;
  • 3、用戶登錄成功後,可以點擊控制器視圖中的註銷按鈕進行註銷操作,所以我們在AppDelegate中提供了一個註銷方法介面給外界
#pragma 用戶註銷
-(void)xmppUserLogout;
  • 4、當我們的用戶狀態改變的時候,要告訴外界,比如,用戶線上時,需要一些處理,所以我們不僅需要將用戶的登錄信息寫入到沙盒中,而且用戶的狀態也要寫入到沙盒中,第二個問題:當我們的用戶狀態改變的時候,我們要告訴控制器,讓控制器進行一些處理操作:又牽扯到通信了,這裡:採用通知告知吧
//登錄狀態改變
#define kLoginStateChangeNotification @"LoginStateChangeNotification"
  • 5、AppDelegate.h頭文件
#import <UIKit/UIKit.h>

#define kIsLoginKey @"isLogin"

//登錄狀態改變
#define kLoginStateChangeNotification @"LoginStateChangeNotification"

#define xmppDelegate ((JPAppDelegate *)[UIApplication sharedApplication].delegate)

typedef enum {
    XMPPResultTypeLogining,//正在登錄中
    XMPPResultTypeLoginSuccess,//登錄成功
    XMPPResultTypeLoginFailure,//登錄失敗
    XMPPResultTypeNetError,//網路不給力
    XMPPResultTypeUnknowDomain,//功能變數名稱不存在
    XMPPResultTypeConnectionRefused//伺服器拒絕連接
}XMPPResultType;
typedef void (^XMPPResultBlock)(XMPPResultType resultType);//xmpp請求結果的block

@interface JPAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;


#pragma mark 用戶登錄
-(void)xmppUserLogin:(XMPPResultBlock)resultBlock;


#pragma 用戶註銷
-(void)xmppUserLogout;

@end

三、AppDelegate.m實現文件

  • 0.在登錄界面點擊登錄按鈕,登錄成功後,進入主界面
  • 1.用戶登錄成功後,退出到後臺時,斷開連接,顯示在前臺時自動連接(添加一個isLogin用戶偏好設置)
  • 2.用戶成功登錄後,如果是重新啟動程式,直接跳到主界面,否則跳到登錄頁面
  • 3.用戶成功登錄後,如果是重新啟動程式,下次啟動時自動登錄
  • 4.用戶登錄失敗時,清除偏好設置
  • 5.用戶登錄失敗時要提示
  • 6.用戶註銷
  • 7.進入登錄頁面時,自動顯示上一次登錄數據

  • 註意:

    • 官方建議,把用戶授權寫在appdelegate 
#import "JPAppDelegate.h"
#import "JPLoginTool.h"


#define kMainStoryboardName @"Main"
#define kLoginStoryboardName @"Login"

@interface JPAppDelegate()<XMPPStreamDelegate>{

    XMPPResultBlock _resultBlock;
}

//初始化xmppStream
-(void)setupXmppStream;

//連接主機
-(void)connectToHost;

//從主機斷開連接
-(void)disconnectFromHost;

//授權(也就發送帳號和密碼)
-(void)userAuth;

//用戶上線(通知其他好友,你已經線上)
-(void)goOnline;

//用戶用戶離線
-(void)goOffline;

@end

@implementation JPAppDelegate

//官方建議,把用戶授權寫在appdelegate
/**
 *  0.初始化xmppStream
 *  1.連接主機
 *  2.從主機斷開連接
 *  3.授權(也就發送帳號和密碼)
 *  4.用戶上線(通知其他好友,你已經線上)
 *  5.用戶用戶離線
 */


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    //NSLog(@"%s %d",__func__,__LINE__);

    //設置日誌輸出方式(輸出到控制器)
    [DDLog addLogger:[DDTTYLogger sharedInstance]];

    //設置顏色
    [[DDTTYLogger sharedInstance] setColorsEnabled:YES];


    //設置自己的日誌顏色
    [[DDTTYLogger sharedInstance] setForegroundColor:[UIColor blueColor] backgroundColor:nil forFlag:LOG_LEVEL_INFO];

    // 初始化xmppStream
    [self setupXmppStream];

    return YES;
}
#pragma 失去焦點
- (void)applicationWillResignActive:(UIApplication *)application
{
    //從主機斷開連接
    //[self disconnectFromHost];

    //獲取登錄狀態
    if([JPLoginTool isLogin]){
        //NSLog(@"登錄過");
        //如果是登錄 斷開連接
        [self disconnectFromHost];
    };
}



#pragma mark 獲取焦點
- (void)applicationDidBecomeActive:(UIApplication *)application
{
    //[self connectToHost];
    //獲取登錄狀態 如果登錄過,直接跳到主頁面 然後自動登錄
    if([JPLoginTool isLogin]){
        NSLog(@"登錄過");
        //直接跳到主頁
        [self showStoryboardWithName:kMainStoryboardName];

        //自動登錄
        [self connectToHost];
    };
}

#pragma mark - xmppSteam代理
#pragma mark 連接成功
-(void)xmppStreamDidConnect:(XMPPStream *)sender{
    JPLogInfo(@"與主機連接成功");
     //JPLogInfo(@"登錄");
     //發送登錄密碼驗證
        [self userAuth];
}

#pragma mark 連接失敗
-(void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error{

    //如果error為空,代理正常斷開
    JPLogInfo(@"連接失敗 %@",error);

    //有error 並且block有值 通知登錄控制器

    if (error && _resultBlock) {
        //功能變數名稱或者主機不存
        if (error.code == 8) {
            _resultBlock(XMPPResultTypeUnknowDomain);
        }else if(error.code == 61){
            _resultBlock(XMPPResultTypeConnectionRefused);
        } else{
            _resultBlock(XMPPResultTypeNetError);
        }
    }

    // 清除用戶偏好設置
    if (error) {
        [JPLoginTool removeAllLoginInfo];
    }
}

#pragma mark 用戶授權成功
-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
   // 子線程
    NSLog(@"%@",[NSThread currentThread]);
    JPLogInfo(@"用戶授權成功");
    // 把"登錄狀態"通知"聊天歷史控制器"
    // 登錄成功
    [self postLoginNotification:XMPPResultTypeLoginSuccess];

    // 1.通知用戶上線
    [self goOnline];

    // 2.如果用戶登錄成功 沙盒裡保存一個登錄狀態
    [JPLoginTool setLogin:YES];

    //在主線程更新UI
    [self showStoryboardWithName:kMainStoryboardName];
}

#pragma mark 用戶授權失敗
-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{
    JPLogInfo(@"用戶授權失敗%@",error);
    //把"登錄狀態"通知"聊天歷史控制器"
    //登錄失敗
    [self postLoginNotification:XMPPResultTypeLoginFailure];

    //清除用戶偏好設置
    [JPLoginTool removeAllLoginInfo];
    //通知登錄控制器
    if (_resultBlock) {
        _resultBlock(XMPPResultTypeLoginFailure);
    }
//    dispatch_async(dispatch_get_main_queue(), ^{
//        
//    });
}

#pragma mark -私有方法

#pragma mark 初始化xmppStrem對象
-(void)setupXmppStream{

    NSAssert(_xmppStream == nil, @"xmppStream對象初始化多次");

    //1.創建xmppStrem對象
    _xmppStream = [[XMPPStream alloc] init];
    //2.添加代表
    [_xmppStream addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
}

-(void)connectToHost{
    JPLogInfo(@"開始連接到主機");

    //把"登錄狀態"通知"聊天歷史控制器"
    //登錄中
    [self postLoginNotification:XMPPResultTypeLogining];

    //從沙盒裡獲取數據
    NSString *account =  [JPLoginTool account];
    NSString *domain = [JPLoginTool domain];

    //1.設置賬號
    _xmppStream.myJID = [XMPPJID jidWithUser:account domain:domain resource:nil];

    //2.設置主機
    _xmppStream.hostName = domain;

    //3.設置主機埠
    //預設埠就5222
    _xmppStream.hostPort = 5222;
    //連接到主機

    NSError *err = nil;
    [_xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&err];
    if (err) {
       JPLogInfo(@"%@ ",err);
    }
}

#pragma mark 從主機斷連接
-(void)disconnectFromHost{
    // 1.通知用戶下線
    [self goOffline];

    // 2.斷開連接
    [_xmppStream disconnect];
}

#pragma mark 用戶授權
-(void)userAuth{
    JPLogInfo(@"用戶開始授權");

    NSError *error = nil;
    //發送密碼到伺服器
    [_xmppStream authenticateWithPassword:[JPLoginTool password] error:&error];

    if (error) {
        JPLogInfo(@"%@",error);
    }
}

#pragma mark 用戶上線
-(void)goOnline{
    JPLogInfo(@"通知用戶線上");
    XMPPPresence *presence  = [XMPPPresence presence];
    [_xmppStream sendElement:presence];
}

#pragma mark 用戶下線
-(void)goOffline{
    JPLogInfo(@"通知用戶下線");
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
    [_xmppStream sendElement:presence];
}

#pragma mark 顯示storyboard的第一個控制器
// 比如用戶登錄成功後,設置主視窗的根控制器為tabVC,然後,選中的tabVC的第三個子控制器,
// 然後退出到後臺,當用戶再次進入到前臺時,並不需要重新設置視窗的根控制器此時。
// 那什麼時候需要設置呢-> 當主視窗的根控制器不是tabVC才需要重新設置視窗的根控制器
-(void)showStoryboardWithName:(NSString *)name{
    dispatch_async(dispatch_get_main_queue(), ^{
        // 3.顯示主界面
        // 3.1獲取sotryboard對象
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:name bundle:nil];

        //3.2獲取windows的舊的根控制器
        UIViewController *oldVc = self.window.rootViewController;
        JPLogWarn(@"舊的控制器 %@",oldVc);

        //3.3獲取要切換storyboard裡面的第一個控制器
        UIViewController *newVc = [storyboard instantiateInitialViewController];

        JPLogWarn(@"要切換的控制器 %@",newVc);

        //如果舊的控制器類型和新的控制器類型不一樣,才須要切換UIWindow的根控制器
        if (![oldVc isKindOfClass:[newVc class]]) {
            //38
            self.window.rootViewController = newVc;
        }
    });
}


#pragma mark -公共方法
#pragma mark 用戶登錄
-(void)xmppUserLogin:(XMPPResultBlock)resultBlock{
    //block負值
    _resultBlock = resultBlock;

    JPLogInfo(@"用戶登錄被調用");
    //如果當前socket存在連接,應該斷開
//    if (_xmppStream.isConnected) {
//        [_xmppStream disconnect];
//    }

    [_xmppStream disconnect];
    [self connectToHost];
}


#pragma mark 用戶註銷
-(void)xmppUserLogout{
    //1.設置登錄狀態為NO
    [JPLoginTool setLogin:NO];

    //2.斷開連接
    [self disconnectFromHost];

    //3.返回到登錄頁面
    [self showStoryboardWithName:@"Login"];
}

#pragma mark 登錄狀態通知
-(void)postLoginNotification:(XMPPResultType)resultType{
    //把"登錄狀態"通知"聊天歷史控制器"
    //登錄成功
    dispatch_async(dispatch_get_main_queue(), ^{
        NSDictionary *userInfo = @{@"LoginState": @(resultType)};

        [[NSNotificationCenter defaultCenter] postNotificationName:kLoginStateChangeNotification object:nil userInfo:userInfo];
    });
}

四、控制器中實現登錄

- (IBAction)login {

    //1.把你登錄信息保存到沙盒裡
    NSString *account = self.accountField.text;
    NSString *password = self.passwordFiled.text;
    NSString *domain = self.domainField.text;

    [JPLoginTool saveLoginInfoWithAccount:account pwd:password domain:domain];

    //隱藏keyboard
    [self.view endEditing:YES];

    //提醒正在登錄
    UIView *showView = self.view;
    [MBProgressHUD showMessage:@"正在登錄......" toView:showView];


    xmppDelegate.userRegister = NO;//代表登錄

    //2.調用appdelegate里的xmmpUserLogin方法
    //JPAppDelegate *delegate = [UIApplication sharedApplication].delegate;
    [xmppDelegate xmppUserLogin:^(XMPPResultType resultType) {
        //隱藏正在登錄
        //因為這個block是被appdelegate裡面xmppStream的代理調用,而xmppStream代理被調用是在子線線程中的,所在更新UI放在主線程
        dispatch_async(dispatch_get_main_queue(), ^{
            [MBProgressHUD hideHUDForView:showView];
            switch (resultType) {
                case XMPPResultTypeLoginFailure:
                    [MBProgressHUD showError:@"用戶名或者密碼錯誤"];
                    break;
                case XMPPResultTypeNetError:
                    [MBProgressHUD showError:@"網路不給力"];
                    break;
                case XMPPResultTypeConnectionRefused:
                    [MBProgressHUD showError:@"伺服器拒絕連接,可能服務沒有開啟"];
                    break;
                case XMPPResultTypeUnknowDomain:
                    JPLogInfo(@"功能變數名稱不存在或者錯誤");
                    [MBProgressHUD showError:@"功能變數名稱不存在或者錯誤"];
                    break;
                default:
                    break;
            }
        });

    }];
}

原文鏈接:http://www.jianshu.com/p/a16d3d70dd86

參考鏈接:http://blog.csdn.net/cerastes/article/details/33713967

            http://blog.csdn.net/liuhongwei123888/article/details/6840262

            http://www.jianshu.com/p/a22406c40c8b

 源碼地址:https://github.com/robbiehanson/XMPPFramework,目前需要使用 Git (sourcTree) 才能download到源碼。

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 微信的圖像有3種JSSDK的API,可以做一些簡單的需求,本節講解一個讓用戶在手機中選擇照片然後分享的項目。 ...
  • 用CSS和jQuery來實現它,儘量看起來和原效果一樣。 最終效果圖 最終效果圖 本教程里,我將使用CSS,HTML和jQuery來創建一個近似Apple TV視差效果,如果你正在閱讀,我假設你對上述三種技術都有基本的瞭解。 廢話不多說,開始第一部分。 HTML頁面 我們的頁面結構像下麵這樣: 首先 ...
  • 1.index.Android.js 2.在項目的 index.android.js同一目錄下 創建json文件 這樣方便圖片的訪問,資源圖片放在項目名稱\android\app\src\main\res\drawable 下麵 這裡的BadgeData.json 如下: 3.主要的文件 scrol ...
  • 我們在瀏覽淘寶京東等大型購物網頁時會經常出現許多圖片而圖片需要花費我們非常多的流量問題。 我們在寫網頁的時候怎麼解決這個問題呢?這時候就要用到我們圖片懶載入的問題,這樣不僅可以 解決流量問題,也提高了性能等等。 下麵我們就來看一下圖片的懶載入怎麼問題。 ...
  • 1.層級選擇器 後代選擇器 "父元素 後代元素" 比如:$("div p") 選取div元素下所有的p元素 子元素選擇器 "父元素 > 子元素" 比如:$("div>p") 選取div的子元素中的p元素 第一個向後兄弟元素 "元素名+兄弟元素" 比如:$("div+p") 選取div元素後的第一個p ...
  • 一.Javascript的含義 是一種解釋性的語言,主要給網頁添加各色各樣的動態功能,同時為用戶提供瀏覽效果。 二.JavaScript的主要特點 三.JavaScript的組成 四.JavaScript的三種引入方式 1.標簽內引入2.內部引入3.外部引入 五.javaScript語法的基本要求 ...
  • nodejs中文網,官網同步翻譯 http://nodejs.cn/api/ Webpack 中文手冊(社區同步翻譯) http://6.course.uprogrammer.cn/webpack2 doc cn/index.html ECMAScript6 中文教程 https://www.w3c ...
  • XMPP詳解 XMPP(eXtensible Messaging and Presence Protocol,可擴展消息處理和現場協議)是一種在兩個地點間傳遞小型結構化數據的協議。在此基礎上,XMPP協議已經被用來構建大規模即時通信系統、游戲平臺、協作空間及語音和視頻會議系統。 XMPP由幾個小的構 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...