前言
上一篇文章我们已经获取到贝乐虎启蒙App
的一些图片资源,这一篇我们就开始封装一下网络请求。在封装之前我们要对虎启蒙App进行抓包,这里我们使用
Charles`,这个相信大家都不陌生吧,如果有不了解的可以看下这篇文章对于Charles的使用
使用Charles
抓包
下面是首页的UI,
我们先来抓个首页
的数据试试,打开app后请求到不少的数据,但是没有首页
顶部的推荐、唱儿歌、看动、读绘本、听故事
,这五个应该是本地写死的
接下来我们分别切换推荐、唱儿歌、看动、读绘本、听故事
来获取数据
现在首页
的数据已经获取到了,接下来我们就开始封装网络请求
网络请求封装
Swift
中网络请求我们使用 Alamofire,然后对其进一步封装。
首先我们使用
CocoaPods
导入Alamofire
库,然后新建一个NetworkManager
网络管理类,引入Alamofire
NetworkManager
是一个单例,里面增加一个dataRequest
字典属性,其key
是请求接口的URL
和参数
组成的,value
是一个请求任务(DataRequest)
,为什么要增加这个属性呢?是因为准备用链式调用,方便后面取出响应数据
import Alamofire
class NetworkManager: NSObject {
static let share = NetworkManager()
private var dataRequest = [String: DataRequest]()
public func request(_ url: String,
method: HTTPMethod = .post,
parameters: Parameters? = nil,
encoding: ParameterEncoding = JSONEncoding.default,
headers: HTTPHeaders? = nil) -> NetworkManager {
let key = requestKey(url, parameters)
let request = AF.request(url,
method: method,
parameters: parameters,
encoding: encoding,
headers: headers)
dataRequest[key] = request
return self
}
public func responseData(completion: @escaping (Data) -> Void,
failure: @escaping (AFError) -> Void) {
dataRequest.forEach { key, request in
dataRequest.removeValue(forKey: key)
request.responseData { response in
switch response.result {
case let .success(data):
completion(data)
case let .failure(error):
failure(error)
}
}
}
}
}
现在已经初步封装完成,先看看能不能请求数据
NetworkManager.share
.request("https://vd.ubestkid.com/api/v1/feature/qmtab_tj3.json", parameters: parameters)
.responseData { data in
debugPrint(data)
} failure: { error in
}
请求是可以的,请求结果这里就不展示了。
虽然说这个网络请求能够使用,但是请求参数和数据返回这块还不够友好,接下来我们对请求参数优化下。
因为每个请求接口都有
url
、method
、parameters
、encoding
、headers
等,所以还是用协议来处理吧
网络请求入参处理
1、新增一个TargetType
协议,因为每个url
里面有公共的部分,所以url
拆成baseURL
和path
public protocol TargetType {
var baseURL: String { get }
var path: String { get }
var method: HTTPMethod { get }
var parameters: [String: Any] { get }
var encoding: ParameterEncoding { get }
var headers: HTTPHeaders? { get }
}
然后给TargetType来个extension,给所有属性一个默认值
extension TargetType {
var baseURL: String {
return "https://vd.ubestkid.com/"
}
var path: String {
return ""
}
var method: HTTPMethod {
return .post
}
var parameters: [String: Any] {
return [:]
}
var encoding: ParameterEncoding {
return JSONEncoding.default
}
var headers: HTTPHeaders? {
return nil
}
}
2、回到NetworkManager
里面,修改request
方法入参
public func request(_ target: TargetType) -> NetworkManager {
let url = target.baseURL + target.path
let key = requestKey(url, target.parameters)
let request = AF.request(url,
method: target.method,
parameters: target.parameters,
encoding: target.encoding,
headers: target.headers)
dataRequest[key] = request
return self
}
在TargetType
的extensio
n里面新增一个request()
方法,在该方法里面调用NetworkManager
的request()
方法
extension TargetType {
func request() -> NetworkManager {
return NetworkManager.share.request(self)
}
}
3、新建一个Network
,接口请求入口,以后接口都按照模块分
struct Network {}
现在就以首页
的接口看下怎么掉用吧,在Network
的extension
里面新增一个枚举Home
,以后首页
的接口都放在Home
里面,Home里面加个lis
t,给个path
参数,因为推荐、唱儿歌、看动、读绘本、听故事
接口就是qmtab_
后面不一样,而且入参都是一样的
推荐: …/api/v1/feature/qmtab_tj3.json
唱儿歌: …/api/v1/feature/qmtab_eg3.json
看动: …/api/v1/feature/qmtab_dh3.json
读绘本: …/api/v1/feature/qmtab_hb3.json
听故事: …/api/v1/feature/qmtab_gs3.json
extension Network {
enum Home {
case list(path: String)
}
}
extension Network.Home: TargetType {
var path: String {
switch self {
case let .list(path):
return "api/v1/feature/qmtab_\(path).json"
}
}
var parameters: [String: Any] {
switch self {
case .list:
return ["mac": "",
"exp10": 60,
"exp2": 1,
"ua": "",
"devicetype": 1,
"srcApp": "com.ubestkid.collection",
"carrier": "46002",
"svip_status": 2,
"impsize": 1,
"exp7": 55,
"exp3": 73,
"version": "4.0",
"make": "apple",
"bannersafe": 0,
"oaid": "",
"sh": 2208,
"network": 1,
"vps": 10,
"sw": 1242,
"cpId": "blh",
"splashsafe": 0,
"channel": "c2",
"exp8": 55,
"pkg": "com.ubestkid.collection",
"exp4": 34,
"model": "iPhone8,2",
"osv": "14.6",
"idfa": "",
"ppi": 401,
"apiVersion": "1.1.0",
"exp9": 37,
"os": 1,
"androidid": "",
"exp5": 39,
"ak": "8f75a52eadde46239f2227ba64eab72b",
"exp1": 58,
"egvip_status": 2,
"age": "1",
"appver": "3.8.3",
"installtime": 1625143625930,
"res_type": 0,
"ip": "",
"imei": "",
"userId": "",
"exp6": 4]
}
}
}
然后掉用就如下面:
Network.Home
.list(path: "tj3")
.request()
.responseData { data in
} failure: { error in
}
数据返回处理
现在是可以正常请求了,但是怎么处理返回的数据呢?这里我们使用苹果地带的Codable
协议,推荐一个CleanJSON库来转成model
,根据首页接口返回的数据,我们建立一个Response
基类,遵守Codable
struct Response<T: Codable>: Codable {
let errorCode: Int
let errorMessage: String
let result: T
var success: Bool {
return errorCode == 0
}
var appError: AppError {
return AppError(code: errorCode, errorMessage: errorMessage)
}
}
回到NetworkManager
里面修改responseData()
方法
public func responseData<T: Codable>(_ type: T.Type,
completion: @escaping (Response<T>) -> Void,
failure: @escaping (AppError) -> Void) {
dataRequest.forEach { key, request in
dataRequest.removeValue(forKey: key)
request.responseData { response in
switch response.result {
case let .success(data):
if let responseData = try? CleanJSONDecoder().decode(Response<T>.self, from: data) {
if !responseData.success {
failure(responseData.appError)
return
}
completion(responseData)
} else {
failure(AppError(code: 0000, errorMessage: "数据解析失败"))
}
case let .failure(error):
failure(error.appError)
}
}
}
}
现在整个网络请求算是封装完成了,最后看下使用吧
Network.Home
.list(path: "tj3")
.request()
.responseData(RecModel.self) { model in
debugPrint(model.result)
} failure: { error in
}
今天的文章使用Swift开发一个贝乐虎启蒙App – 网络请求封装分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/13926.html