iOS--React Native网络请求插件

简介: React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的JS框架 React 在原生移动应用平台的衍生产物,目前支持iOS和安卓两大平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可以进入移动应用开发领域。

一:介绍

React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的JS框架 React 在原生移动应用平台的衍生产物,目前支持iOS和安卓两大平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可以进入移动应用开发领域。

在React Native移动平台项目开发中,除了React Native 提供的封装好的部分插件和原声组建外,在实际的项目中还需要使用到很多其他的插件,比如网络请求、数据库、相机、相册、通讯录、视频播放器、浏览器、蓝牙连接、图片处理、消息推送、地图、统计、埋点等等APP开发中需要用到的功能,都为IDE开发平台提供封装好的插件,以便项目开发使用。

另外,这些博文都是来源于我日常开发中的技术总结,在时间允许的情况下,我会针对技术点分别分享iOS、Android两个版本,如果有其他技术点需要,可在文章后留言,我会尽全力帮助大家。这篇文章重点介绍网络请求插件的开发与使用

源码Demo获取方法

如果需要React Native网络请求插件源码demo,欢迎关注 【网罗开发】微信公众号,回复【65】便可领取。

网罗天下方法,方便你我开发,所有文档会持续更新,欢迎关注一起成长!

二:实现思路分析

网络请求插件是需要实现前端与服务端的数据交互,其中包括GET请求、POST请求、文件上传、单/多张图片上传、文件下载等功能。这些功能将通过封装后的方法暴漏出来,通过RN接口提供给Javascript开发使用。

具体的实现思路如下:

  1. 新建NetWorkPlugin类,实现RCTBridgeModule协议
  2. 添加RCT_EXPORT_MODULE()宏
  3. 添加React Native跟控制器
  4. 声明被JavaScript 调用的方法
  5. 导入AFNetworking请求库
  6. 新建NetworkHelper类,封装实现网络请求功能
  7. 实现GET请求
  8. 实现POST请求
  9. 实现文件上传
  10. 实现单/多张图片上传
  11. 实现文件下载
  12. Javascript调用浏览器方法

三:实现源码分析

1. 新建NetWorkPlugin类,实现RCTBridgeModule协议

新建继承NSObject的NetWorkPlugin类,并实现RCTBridgeModule协议

// NetWorkPlugin.h
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <UIKit/UIKit.h>
@interface NetWorkPlugin : NSObject<RCTBridgeModule>
@end

2. 添加RCT_EXPORT_MODULE()宏

为了实现RCTBridgeModule协议,NetWorkPlugin的类需要包含RCT_EXPORT_MODULE()宏。
并在这个宏里面添加一个参数“NetWorkPlugin”用来指定在 JavaScript 中访问这个模块的名字。
如果你不指定,默认就会使用这个 Objective-C 类的名字。
如果类名以 RCT 开头,则 JavaScript 端引入的模块名会自动移除这个前缀。

// NetWorkPlugin.m
#import "NetWorkPlugin.h"
@implementation NetWorkPlugin
RCT_EXPORT_MODULE(NetWorkPlugin);
@end

3. 添加React Native跟控制器

如果不添加React Native跟控制器,view将不能正常显示出来,实现方法如下:

// NetWorkPlugin.m
#import <React/RCTUtils.h>

引入<React/RCTUtils.h>之后,在视图初始化或者显示的时候,按照如下方法调用即可

UIViewController *vc = RCTPresentedViewController();

4. 声明被JavaScript 调用的方法

React Native需要明确的声明要给 JavaScript 导出的方法,否则 React Native 不会导出任何方法。下面通过举例来展示声明的方法,通过RCT_EXPORT_METHOD()宏来实现:

// NetWorkPlugin.m
#import "NetWorkPlugin.h"
#import <React/RCTUtils.h>
@implementation NetWorkPlugin
RCT_EXPORT_MODULE(NetWorkPlugin);
RCT_EXPORT_METHOD(post:(NSDictionary *)arguments
                  withCompletionHandler:(RCTResponseSenderBlock)completion
                  failureHandler:(RCTResponseSenderBlock)failure)
{
    NSLog(@"POST网络请求执行方法");
}
@end

5. 导入AFNetworking请求库

网络请求使用的第三方库是AFNetworking,这个库很常见,也比较常用,就不做过多的描述,可手动导入也可使用cocoapods自动导入,导入之后在.m文件中引入头文件。

6. 新建NetworkHelper类,封装实现网络请求功能

新建继承NSObject的NetworkHelper类,定义枚举类型来判断网络状态:

typedef NS_ENUM(NSUInteger, NetworkStatusType) {
    /** 未知网络*/
    NetworkStatusUnknown,
    /** 无网络*/
    NetworkStatusNotReachable,
    /** 手机网络*/
    NetworkStatusReachableViaWWAN,
    /** WIFI网络*/
    NetworkStatusReachableViaWiFi
};

定义网络状态的Block

typedef void(^NetworkStatus)(NetworkStatusType status);

实时获取网络状态,通过Block回调实时获取(此方法可多次调用)

+ (void)networkStatusWithBlock:(NetworkStatus)networkStatus;

7. 实现GET请求

声明GET请求方法:

/**
 *
 *  @param URL        请求地址
 *  @param parameters 请求参数
 *  @param success    请求成功的回调
 *  @param failure    请求失败的回调
 *
 *  @return 返回的对象可取消请求,调用cancel方法
 */
+ (__kindof NSURLSessionTask *)GET:(NSString *)URL
                        parameters:(id)parameters
                           success:(HttpRequestSuccess)success
                           failure:(HttpRequestFailed)failure;

8. 实现POST请求

声明POST请求方法:

/**
 *
 *  @param URL        请求地址
 *  @param parameters 请求参数
 *  @param success    请求成功的回调
 *  @param failure    请求失败的回调
 *
 *  @return 返回的对象可取消请求,调用cancel方法
 */
+ (__kindof NSURLSessionTask *)POST:(NSString *)URL
                         parameters:(id)parameters
                            success:(HttpRequestSuccess)success
                            failure:(HttpRequestFailed)failure;

POST请求具体的方法实现如下:

+ (NSURLSessionTask *)POST:(NSString *)URL
                parameters:(id)parameters
                   success:(HttpRequestSuccess)success
                   failure:(HttpRequestFailed)failure {
    NSString *AllReplaceURL = [self replaceURL:URL];
    [self setAFHTTPSessionManagerProperty:^(AFHTTPSessionManager *sessionManager) {
        [sessionManager.requestSerializer setQueryStringSerializationWithBlock:^NSString * _Nonnull(NSURLRequest * _Nonnull request, id  _Nonnull parameters, NSError * _Nullable __autoreleasing * _Nullable error) {
            return parameters;
        }];
    }];
    NSURLSessionTask *sessionTask = [_sessionManager POST:AllReplaceURL parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        if (_isOpenLog) {NSLog(@"responseObject = %@",[self jsonToString:responseObject]);}
        [[self allSessionTask] removeObject:task];
        success ? success(responseObject) : nil;
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        if (_isOpenLog) {NSLog(@"error = %@",error);}
        [[self allSessionTask] removeObject:task];
        failure ? failure(error) : nil;
        
    }];
    sessionTask ? [[self allSessionTask] addObject:sessionTask] : nil ;
    return sessionTask;
}

9. 实现文件上传

声明文件上传方法:

/**
 * 
 *  @param URL        请求地址
 *  @param parameters 请求参数
 *  @param names       文件对应服务器上的字段
 *  @param filePaths   文件本地的沙盒路径
 *  @param progress   上传进度信息
 *  @param success    请求成功的回调
 *  @param failure    请求失败的回调
 *
 *  @return 返回的对象可取消请求,调用cancel方法
 */
+ (__kindof NSURLSessionTask *)uploadFileWithURL:(NSString *)URL
                                      parameters:(id)parameters
                                            names:(NSArray<NSString *> *)names
                                        filePaths:(NSArray<NSString *> *)filePaths
                                        progress:(HttpProgress)progress
                                         success:(HttpRequestSuccess)success
                                         failure:(HttpRequestFailed)failure;

文件上传具体的方法实现如下:

+ (NSURLSessionTask *)uploadFileWithURL:(NSString *)URL
                             parameters:(id)parameters
                                  names:(NSArray<NSString *> *)names
                              filePaths:(NSArray<NSString *> *)filePaths
                               progress:(HttpProgress)progress
                                success:(HttpRequestSuccess)success
                                failure:(HttpRequestFailed)failure {
    
    NSString *AllReplaceURL = [self replaceURL:URL];
    
    NSURLSessionTask *sessionTask = [_sessionManager POST:AllReplaceURL parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        NSError *error = nil;
        for (NSUInteger i = 0; i < filePaths.count; i++) {
            NSString *name = names[i];
            NSString *filePath = filePaths[i];
            [formData appendPartWithFileURL:[NSURL fileURLWithPath:filePath] name:name error:&error];
        }
        (failure && error) ? failure(error) : nil;
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        //上传进度
        dispatch_sync(dispatch_get_main_queue(), ^{
            progress ? progress(uploadProgress) : nil;
        });
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        if (_isOpenLog) {NSLog(@"responseObject = %@",[self jsonToString:responseObject]);}
        [[self allSessionTask] removeObject:task];
        success ? success(responseObject) : nil;
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        if (_isOpenLog) {NSLog(@"error = %@",error);}
        [[self allSessionTask] removeObject:task];
        failure ? failure(error) : nil;
    }];
    sessionTask ? [[self allSessionTask] addObject:sessionTask] : nil ;
    return sessionTask;
}

10. 实现单/多张图片上传

声明单/多张图片上传方法:

/**
 *
 *  @param URL        请求地址
 *  @param parameters 请求参数
 *  @param name       图片对应服务器上的字段
 *  @param images     图片数组
 *  @param fileNames  图片文件名数组, 可以为nil, 数组内的文件名默认为当前日期时间"yyyyMMddHHmmss"
 *  @param imageScale 图片文件压缩比 范围 (0.f ~ 1.f)
 *  @param imageType  图片文件的类型,例:png、jpg(默认类型)....
 *  @param progress   上传进度信息
 *  @param success    请求成功的回调
 *  @param failure    请求失败的回调
 *
 *  @return 返回的对象可取消请求,调用cancel方法
 */
+ (__kindof NSURLSessionTask *)uploadImagesWithURL:(NSString *)URL
                                        parameters:(id)parameters
                                              name:(NSString *)name
                                            images:(NSArray<UIImage *> *)images
                                         fileNames:(NSArray<NSString *> *)fileNames
                                        imageScale:(CGFloat)imageScale
                                         imageType:(NSString *)imageType
                                          progress:(HttpProgress)progress
                                           success:(HttpRequestSuccess)success
                                           failure:(HttpRequestFailed)failure;

图片经过等比压缩后得到的二进制文件,默认图片的文件名, 若fileNames为nil就使用,单/多张图片上传具体的方法实现如下:

+ (NSURLSessionTask *)uploadImagesWithURL:(NSString *)URL
                               parameters:(id)parameters
                                     name:(NSString *)name
                                   images:(NSArray<UIImage *> *)images
                                fileNames:(NSArray<NSString *> *)fileNames
                               imageScale:(CGFloat)imageScale
                                imageType:(NSString *)imageType
                                 progress:(HttpProgress)progress
                                  success:(HttpRequestSuccess)success
                                  failure:(HttpRequestFailed)failure {
    
    NSString *AllReplaceURL = [self replaceURL:URL];
    
    NSURLSessionTask *sessionTask = [_sessionManager POST:AllReplaceURL parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        
        for (NSUInteger i = 0; i < images.count; i++) {
            NSData *imageData = UIImageJPEGRepresentation(images[i], imageScale ?: 1.f);

            NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
            formatter.dateFormat = @"yyyyMMddHHmmss";
            NSString *str = [formatter stringFromDate:[NSDate date]];
            NSString *imageFileName = NSStringFormat(@"%@%ld.%@",str,i,imageType?:@"jpg");
            
            [formData appendPartWithFileData:imageData
                                        name:name
                                    fileName:fileNames ? NSStringFormat(@"%@.%@",fileNames[i],imageType?:@"jpg") : imageFileName
                                    mimeType:NSStringFormat(@"image/%@",imageType ?: @"jpg")];
        }
        
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        dispatch_sync(dispatch_get_main_queue(), ^{
            progress ? progress(uploadProgress) : nil;
        });
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        if (_isOpenLog) {NSLog(@"responseObject = %@",[self jsonToString:responseObject]);}
        [[self allSessionTask] removeObject:task];
        success ? success(responseObject) : nil;
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        if (_isOpenLog) {NSLog(@"error = %@",error);}
        [[self allSessionTask] removeObject:task];
        failure ? failure(error) : nil;
    }];
    sessionTask ? [[self allSessionTask] addObject:sessionTask] : nil ;
    return sessionTask;
}

11. 实现文件下载

声明文件下载方法:

/**
 *
 *  @param URL      请求地址
 *  @param fileDir  文件存储目录(默认存储目录为Download)
 *  @param progress 文件下载的进度信息
 *  @param success  下载成功的回调(回调参数filePath:文件的路径)
 *  @param failure  下载失败的回调
 *
 *  @return 返回NSURLSessionDownloadTask实例,可用于暂停继续,暂停调用suspend方法,开始下载调用resume方法
 */
+ (__kindof NSURLSessionTask *)downloadWithURL:(NSString *)URL
                                       fileDir:(NSString *)fileDir
                                      progress:(HttpProgress)progress
                                       success:(void(^)(NSString *filePath))success
                                       failure:(HttpRequestFailed)failure;

在下载过程中可以获取到下载进度,下载流程为:缓存目录拼接完成,打开文件管理器,创建Download目录,拼接文件路径,返回文件位置的URL路径。文件下载具体的方法实现如下:

+ (NSURLSessionTask *)downloadWithURL:(NSString *)URL
                              fileDir:(NSString *)fileDir
                             progress:(HttpProgress)progress
                              success:(void(^)(NSString *))success
                              failure:(HttpRequestFailed)failure {
    NSString *AllReplaceURL = [self replaceURL:URL];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:AllReplaceURL]];
    __block NSURLSessionDownloadTask *downloadTask = [_sessionManager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        dispatch_sync(dispatch_get_main_queue(), ^{
            progress ? progress(downloadProgress) : nil;
        });
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        NSString *downloadDir = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:fileDir ? fileDir : @"Download"];
        
        NSFileManager *fileManager = [NSFileManager defaultManager];
        
        [fileManager createDirectoryAtPath:downloadDir withIntermediateDirectories:YES attributes:nil error:nil];
        
        NSString *filePath = [downloadDir stringByAppendingPathComponent:response.suggestedFilename];
        
        return [NSURL fileURLWithPath:filePath];
        
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        
        [[self allSessionTask] removeObject:downloadTask];
        if(failure && error) {failure(error) ; return ;};
        success ? success(filePath.absoluteString /** NSURL->NSString*/) : nil;
        
    }];
    [downloadTask resume];
    downloadTask ? [[self allSessionTask] addObject:downloadTask] : nil ;
    
    return downloadTask;
}

12. Javascript调用浏览器方法

现在从 Javascript 里可以这样调用这个方法:

import { NativeModules } from "react-native";
const NetWorkPlugin = NativeModules.NetWorkPlugin;
NetworkPlugin.post({url:"http://192.168.1.1:8080/ApiSystem/login",params:{name:"15842137500",login_type:"0",password:"000000"},headers:{}},(msg) => {
                                         Alert.alert(JSON.stringify(msg));

                                         },(err) => {
                                         Alert.alert(JSON.stringify(err));
                                         });
希望可以帮助大家,如有问题可加QQ技术交流群: 668562416

如果哪里有什么不对或者不足的地方,还望读者多多提意见或建议

如需转载请联系我,经过授权方可转载,谢谢

本篇已同步到个人博客:FBY展菲

目录
相关文章
|
22天前
|
JavaScript 前端开发 iOS开发
ios样式开关按钮jQuery插件
ios样式开关按钮jQuery插件
50 7
|
4月前
针对react-captcha-code第三方插件不能每次触发深颜色的处理
针对`react-captcha-code`插件生成浅色验证码的问题,通过改造成class组件`MyCaptcha.js`,自定义颜色和验证码生成逻辑,解决了颜色问题。
43 1
针对react-captcha-code第三方插件不能每次触发深颜色的处理
|
5月前
|
安全 网络安全 Android开发
安卓与iOS开发:选择的艺术网络安全与信息安全:漏洞、加密与意识的交织
【8月更文挑战第20天】在数字时代,安卓和iOS两大平台如同两座巍峨的山峰,分别占据着移动互联网的半壁江山。它们各自拥有独特的魅力和优势,吸引着无数开发者投身其中。本文将探讨这两个平台的特点、优势以及它们在移动应用开发中的地位,帮助读者更好地理解这两个平台的差异,并为那些正在面临选择的开发者提供一些启示。
132 56
|
4月前
|
前端开发 Python
React技术栈-React路由插件之自定义组件标签
关于React技术栈中React路由插件自定义组件标签的教程。
72 4
React技术栈-React路由插件之自定义组件标签
|
4月前
|
Kubernetes 容器 Perl
Kubernetes网络插件体系及flannel基础
文章主要介绍了Kubernetes网络插件体系,特别是flannel网络模型的工作原理、配置和测试方法。
126 3
|
4月前
|
前端开发 程序员 API
React技术栈-React路由插件之react-router的基本使用
这篇博客介绍了React路由插件react-router的基本使用,包括其概念、API、以及如何通过实战案例在React应用中实现SPA(单页Web应用)的路由管理。
93 9
|
5月前
|
前端开发 C++
使用 Vite 创建 React+TS+SW 项目并整合 AntDesign 、Scss 等组件或插件
本文记录了如何使用Vite创建一个React+TypeScript+Service Workers(SW)项目,并整合AntDesign组件库和Scss等插件,包括项目的创建、配置问题解决、AntDesign和Scss的整合方法。
337 1
|
5月前
|
存储 canal Kubernetes
在K8S中,什么是CNI?平时K8s集群常用什么网络插件?
在K8S中,什么是CNI?平时K8s集群常用什么网络插件?
|
5月前
|
大数据 RDMA
神龙大数据加速引擎MRACC问题之MRACC-Spark利用eRDMA近网络优化插件来提升性能如何解决
神龙大数据加速引擎MRACC问题之MRACC-Spark利用eRDMA近网络优化插件来提升性能如何解决
55 0
|
6月前
|
缓存 安全 Web App开发
Chrome插件实现问题之网络进程接收到URL请求后会如何解决
Chrome插件实现问题之网络进程接收到URL请求后会如何解决

热门文章

最新文章