Selaa lähdekoodia

pod需要的依赖导入

moya以及其他网络请求的封装
mvvm模式样例实现
教师登录接口调用成功实现
main
jasonsyf 1 vuosi sitten
vanhempi
commit
57c4d34802

+ 47
- 0
Podfile Näytä tiedosto

@@ -0,0 +1,47 @@
1
+# Uncomment the next line to define a global platform for your project
2
+# platform :ios, '9.0'
3
+
4
+target 'iOSFirst' do
5
+  # Comment the next line if you don't want to use dynamic frameworks
6
+  use_frameworks!
7
+
8
+  # Pods for iOSFirst
9
+  pod 'SwiftyBeaver'
10
+  pod 'RxSwift', '6.5.0'
11
+  pod 'RxCocoa', '6.5.0'
12
+  pod 'SDWebImage'
13
+  pod 'Kingfisher', '~> 7.1.2'
14
+  # 网络请求
15
+  pod 'Moya/RxSwift'
16
+  pod 'HandyJSON', '~> 5.0.2'
17
+  pod 'SwiftyJSON'
18
+  #分页
19
+  pod 'DNSPageView', '~> 1.0.1'
20
+  #tabbar样式
21
+  pod 'ESTabBarController-swift', '~> 2.6.2'
22
+  #banner滚动图片
23
+  pod 'FSPagerView'
24
+  #跑马灯
25
+  pod 'JXMarqueeView'
26
+  #滚动页
27
+  pod 'LTScrollView'
28
+  pod 'MJRefresh'
29
+  #pod 'SkeletonView'
30
+  #消息提示
31
+  #pod 'SwiftMessages','~> 4.1.4'
32
+  #pod 'YYKit'
33
+  pod 'SVProgressHUD'
34
+  #播放网络音频
35
+  pod 'StreamingKit'
36
+  pod 'RxNetworks'
37
+  #pod 'Toast-Swift', '~> 5.0.1'
38
+ #target 'iOSFirstTests' do
39
+    #inherit! :search_paths
40
+    #Pods for testing
41
+  #end
42
+
43
+  #target 'iOSFirstUITests' do
44
+    # Pods for testing
45
+  #end
46
+
47
+end

+ 1
- 1
iOSFirst.xcodeproj/xcuserdata/sunyufeng.xcuserdatad/xcschemes/xcschememanagement.plist Näytä tiedosto

@@ -7,7 +7,7 @@
7 7
 		<key>iOSFirst.xcscheme_^#shared#^_</key>
8 8
 		<dict>
9 9
 			<key>orderHint</key>
10
-			<integer>18</integer>
10
+			<integer>23</integer>
11 11
 		</dict>
12 12
 	</dict>
13 13
 </dict>

+ 1
- 1
iOSFirst/iOSFirstApp.swift Näytä tiedosto

@@ -9,7 +9,7 @@ import SwiftUI
9 9
 
10 10
 class AppDelegate: NSObject, UIApplicationDelegate {
11 11
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
12
-        Thread.sleep(forTimeInterval: 2)
12
+        Thread.sleep(forTimeInterval: 1.5)
13 13
         return true
14 14
     }
15 15
     func applicationDidReceiveMemoryWarning(_ application: UIApplication) {

+ 21
- 12
iOSFirst/login/LoginView.swift Näytä tiedosto

@@ -6,9 +6,14 @@
6 6
 //
7 7
 
8 8
 import SwiftUI
9
+import RxSwift
10
+import RxCocoa
11
+import RxRelay
9 12
 
10 13
 struct LoginView: View {
11
-   
14
+    private var viewModel = LoginViewModel()
15
+    var bag = DisposeBag()
16
+    
12 17
     
13 18
     var body: some View {
14 19
         
@@ -31,10 +36,11 @@ struct LoginView: View {
31 36
             
32 37
             HStack{
33 38
                 Image("app_logo")
39
+                    .resizable()
34 40
                     .imageScale(.large)
35 41
                     .foregroundColor(.accentColor)
36
-                    .scaledToFit()
37
-                    .frame(width: 40)
42
+                    .scaledToFill()
43
+                    .frame(width: 50,height: 50)
38 44
                 
39 45
                 Image("txtlogo")
40 46
                     .imageScale(.large)
@@ -51,6 +57,7 @@ struct LoginView: View {
51 57
                         .foregroundColor(.accentColor)
52 58
                     
53 59
                     TextField("请输入手机号",text:.constant(""))
60
+                        .id("etPhoneNum")
54 61
                         .font(.system(size: 16))
55 62
                         .frame(maxWidth: .infinity,alignment: .center)
56 63
                     
@@ -67,6 +74,7 @@ struct LoginView: View {
67 74
                         .foregroundColor(.accentColor)
68 75
                     
69 76
                     TextField("请输入密码",text:.constant(""))
77
+                        .id("etPassword")
70 78
                         .font(.system(size: 16))
71 79
                         .frame(maxWidth: .infinity,alignment: .center)
72 80
                     
@@ -81,13 +89,14 @@ struct LoginView: View {
81 89
                 
82 90
                 VStack(alignment: .center, spacing: 15) {
83 91
                     Button(action: {
84
-                        let msg="点击了登录按钮"
85
-                        print(msg)
86
-                        SUIToast.show(messageItem: .init(
87
-                            message: msg,
88
-                            bgColor: .gray,
89
-                            messageColor: .white
90
-                        ))
92
+//                        let msg="点击了登录按钮"
93
+//                        print(msg)
94
+                        viewModel.loginUser()
95
+//                        SUIToast.show(messageItem: .init(
96
+//                            message: msg,
97
+//                            bgColor: .gray,
98
+//                            messageColor: .white
99
+//                        ))
91 100
                     }) {
92 101
                         Text("登录")
93 102
                             .font(.system(size: 17))
@@ -129,11 +138,10 @@ struct LoginView: View {
129 138
                 
130 139
             }
131 140
             Spacer()
132
-            
133 141
         }.padding()
134 142
             .frame(width: .infinity,height: .infinity)
135 143
     }
136
-    
144
+
137 145
 }
138 146
 
139 147
 struct ContentView_Previews: PreviewProvider {
@@ -143,3 +151,4 @@ struct ContentView_Previews: PreviewProvider {
143 151
 }
144 152
 
145 153
 
154
+

+ 44
- 100
iOSFirst/login/LoginViewModel.swift Näytä tiedosto

@@ -1,101 +1,45 @@
1
-////
2
-////  LoginViewModel.swift
3
-////  iOSFirst
4
-////
5
-////  Created by 孙宇峰 on 2023/2/3.
6
-////
7 1
 //
8
-//import Foundation
9
-//import Moya
10
-//import RxSwift
11
-//import RxCocoa
12
-//import RxRelay
13
-//
14
-//struct LoginViewModel  {
15
-//
16
-//    struct Input {
17
-//        private let service:MoyaProvider<AccountService>
18
-//        let loginTrigger: PublishSubject<Void>
19
-//    }
20
-//
21
-//    struct Output {
22
-//    }
23
-//
24
-//    // 用户名称
25
-//    let username = BehaviorRelay(value: "admin")
26
-//    // 用户密码
27
-//    let password = BehaviorRelay(value: "123456")
28
-//
29
-//   
30
-//
31
-//    // 当前用户信息保存
32
-//    var userInfoSaved = PublishSubject<Void>()
33
-//
34
-//    func transform(input: Input) -> Output {
35
-//        let result = input.self.service.rx.request(AccountService.login(username, password, true))
36
-//                    .map(BaseModel<LoginUserInfo>.self)
37
-//                    .map{ $0.data }
38
-//                    .compactMap { $0 }
39
-//                    .asObservable()
40
-//                    .asSingle()
41
-//        let loginRequest = input.loginTrigger.flatMapLatest { [weak self] in
42
-//            guard let self = self else { return Observable.just(RxSwift.Event.next(TokenEnhancer())) }
43
-//            return self.httpRequest.requestAccessToken(username: self.username.value, password: self.password.value)
44
-//                .trackActivity(self.loading)
45
-//                .materialize()
46
-//        }.share()
47
-//
48
-//        // 登录成功
49
-//        loginRequest.elements().subscribe(onNext: { [weak self] tokenEnhancer in
50
-//            AuthManager.setTokenEnhancer(tokenEnhancer: tokenEnhancer)
51
-//            self?.userInfoSaved.onNext(())
52
-//        }).disposed(by: rx.disposeBag)
53
-//
54
-//        // 获取当前用户信息
55
-//        let getUserInfo = userInfoSaved.flatMapLatest { [weak self] in
56
-//            guard let self = self else { return Observable.just(RxSwift.Event.next(BaseResultResponseObject<User>())) }
57
-//            return self.httpRequest.getUserInfo()
58
-//                .trackActivity(self.loading)
59
-//                .materialize()
60
-//        }.share()
61
-//
62
-//        // 获取用户成功
63
-//        getUserInfo.elements().subscribe(onNext: { [weak self] result in
64
-//            guard let self = self else { return }
65
-//            if result.code == result.SUCCESS, let user = result.data {
66
-//                user.saveUserInfo()
67
-//                let application: Application = DIContainer.shared.resolve()
68
-//                let homeTabBarVC: HomeTabBarViewController = HomeTabBarViewController(viewModel: HomeTabBarViewModel())
69
-//                let initialSplitVC: InitialSplitViewController = InitialSplitViewController(viewModel: nil)
70
-//                let navigationC = NavigationController(rootViewController: initialSplitVC)
71
-//                let splitVC = SplitViewController()
72
-//                splitVC.viewControllers = [homeTabBarVC, navigationC]
73
-//
74
-//                // xxx:临时解决方案 RAMAnimatedTabBarController 首次加载需适配当前设备,会导致短暂闪白,延长动画时间
75
-//                UIView.transition(with: application.window!,
76
-//                                  duration: UserDefaults.standard.integer(forKey: Configs.CacheKey.firstLoadKey) == 0 ? 2.3 : 0.5,
77
-//                                  options: .transitionCrossDissolve, animations: {
78
-//                    application.window!.rootViewController = splitVC
79
-//                }, completion: nil)
80
-//
81
-//                // 更新首次加载状态
82
-//                if UserDefaults.standard.integer(forKey: Configs.CacheKey.firstLoadKey) == 0 {
83
-//                    UserDefaults.standard.set(1, forKey: Configs.CacheKey.firstLoadKey)
84
-//                }
85
-//            } else {
86
-//                self.requestError.onNext(ApiError(result.code, result.msg))
87
-//            }
88
-//        }).disposed(by: rx.disposeBag)
89
-//
90
-//        // 登录失败
91
-//        loginRequest.errors().bind(to: bindConverRequestError).disposed(by: rx.disposeBag)
92
-//        // 获取用户失败
93
-//        getUserInfo.errors().bind(to: bindConverRequestError).disposed(by: rx.disposeBag)
94
-//        requestError.subscribe(onNext: { (error) in
95
-//            User.removeUserInfo()
96
-//            AuthManager.removeTokenEnhancer()
97
-//        }).disposed(by: rx.disposeBag)
98
-//
99
-//        return Output()
100
-//    }
101
-//}
2
+//  LoginViewModel.swift
3
+//  iOSFirst
4
+//
5
+//  Created by 孙宇峰 on 2023/2/3.
6
+//
7
+
8
+import Foundation
9
+import Moya
10
+import RxSwift
11
+import RxCocoa
12
+import RxRelay
13
+
14
+
15
+class LoginViewModel  {
16
+
17
+    private let service:MoyaProvider<AccountService>
18
+       private var bag = DisposeBag()
19
+       var userResponse = PublishSubject<LoginUserInfo>()
20
+       
21
+    init(service:MoyaProvider<AccountService> = accountProvider) {
22
+           self.service = service
23
+          
24
+       }
25
+       
26
+     
27
+    func loginUser() {
28
+           service.rx.request(.login("90012", "123456",false)).subscribe { [weak self] event in
29
+               switch event {
30
+               case let .success(response):
31
+                   do {
32
+                       let response = try response.mapJSON()
33
+                       log.info( response )
34
+                       
35
+                   } catch let error {
36
+                       log.error(error.localizedDescription)
37
+                   }
38
+               case .failure(let error):
39
+                   log.error(error.localizedDescription)
40
+               }
41
+           }.disposed(by: bag)
42
+
43
+       }
44
+       
45
+}

+ 2
- 2
iOSFirst/network/API.swift Näytä tiedosto

@@ -8,9 +8,9 @@
8 8
 import Foundation
9 9
 enum Api {
10 10
     /// baseUrl
11
-    static let shoolurl = "https://schooltestapi.xhkjedu.com/"
11
+    static let shoolurl = "https://schoolapitest.xhkjedu.com/"
12 12
     
13
-    static let fileurl = "https://schoolteststatic.xhkjedu.com/static/"
13
+    static let fileurl = "https://schoolstatictest.xhkjedu.com/static/"
14 14
     
15 15
     static let rzurl = "http://scapitest.xhkjedu.com/"
16 16
     

+ 96
- 0
iOSFirst/network/NetworkManager.swift Näytä tiedosto

@@ -0,0 +1,96 @@
1
+//
2
+//  NetworkManager.swift
3
+//  iOSFirst
4
+//
5
+//  Created by 孙宇峰 on 2023/2/22.
6
+//
7
+
8
+import Foundation
9
+import Moya
10
+import Alamofire
11
+import SwiftyJSON
12
+
13
+/// 超时时长
14
+private var requestTimeOut:Double = 30
15
+///endpointClosure
16
+private let myEndpointClosure = { (target: AccountService) -> Endpoint in
17
+///这里的endpointClosure和网上其他实现有些不太一样。
18
+///主要是为了解决URL带有?无法请求正确的链接地址的bug
19
+    let url = target.baseURL.absoluteString + target.path
20
+    var endpoint = Endpoint(
21
+        url: url,
22
+        sampleResponseClosure: { .networkResponse(200, target.sampleData) },
23
+        method: target.method,
24
+        task: target.task,
25
+        httpHeaderFields: target.headers
26
+    )
27
+    switch target {
28
+    default:
29
+        requestTimeOut = 30//设置默认的超时时长
30
+        return endpoint
31
+    }
32
+}
33
+
34
+private let requestClosure = { (endpoint: Endpoint, done: MoyaProvider.RequestResultClosure) in
35
+    do {
36
+        var request = try endpoint.urlRequest()
37
+        //设置请求时长
38
+        request.timeoutInterval = requestTimeOut
39
+        // 打印请求参数
40
+        if let requestData = request.httpBody {
41
+            log.info("\(request.url!)"+"\n"+"\(request.httpMethod ?? "")"+"发送参数"+"\(String(data: request.httpBody!, encoding: String.Encoding.utf8) ?? "")")
42
+        }else{
43
+            log.info("\(request.url!)"+"\(String(describing: request.httpMethod))")
44
+        }
45
+        done(.success(request))
46
+    } catch {
47
+        done(.failure(MoyaError.underlying(error, nil)))
48
+    }
49
+}
50
+
51
+/*   设置ssl
52
+let policies: [String: ServerTrustPolicy] = [
53
+    "example.com": .pinPublicKeys(
54
+        publicKeys: ServerTrustPolicy.publicKeysInBundle(),
55
+        validateCertificateChain: true,
56
+        validateHost: true
57
+    )
58
+]
59
+*/
60
+
61
+// 用Moya默认的Manager还是Alamofire的Manager看实际需求。HTTPS就要手动实现Manager了
62
+//private public func defaultAlamofireManager() -> Manager {
63
+//
64
+//    let configuration = URLSessionConfiguration.default
65
+//
66
+//    configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
67
+//
68
+//    let policies: [String: ServerTrustPolicy] = [
69
+//        "ap.grtstar.cn": .disableEvaluation
70
+//    ]
71
+//    let manager = Alamofire.SessionManager(configuration: configuration,serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies))
72
+//
73
+//    manager.startRequestsImmediately = false
74
+//
75
+//    return manager
76
+//}
77
+
78
+
79
+/// NetworkActivityPlugin插件用来监听网络请求
80
+private let networkPlugin = NetworkActivityPlugin.init { (changeType, targetType) in
81
+
82
+    log.info("networkPlugin \(changeType)")
83
+    //targetType 是当前请求的基本信息
84
+    switch(changeType){
85
+    case .began:
86
+        log.info("开始请求网络")
87
+        
88
+    case .ended:
89
+        log.info("结束")
90
+    }
91
+}
92
+
93
+// https://github.com/Moya/Moya/blob/master/docs/Providers.md  参数使用说明
94
+//stubClosure   用来延时发送网络请求
95
+
96
+let accountProvider = MoyaProvider<AccountService>(endpointClosure: myEndpointClosure, requestClosure: requestClosure, plugins: [networkPlugin], trackInflights: false)

+ 25
- 8
iOSFirst/network/service/AccountService.swift Näytä tiedosto

@@ -35,30 +35,47 @@ extension AccountService: TargetType {
35 35
         }
36 36
     }
37 37
     
38
-    var sampleData: Data {
39
-        return Data()
40
-    }
41
-    
38
+//    var sampleData: Data {
39
+//        return Data()
40
+//    }
41
+//
42 42
     var task: Task {
43 43
         switch self {
44 44
         case .login(let username, let password, _):
45
+        
45 46
             return .requestParameters(parameters: ["loginname": username,
46 47
                                                    "loginpwd": password,
47 48
                                                    "ultype":"p_phone_t",
48
-                                                   "versionnum":"1.0.0"],
49
-                                      encoding: URLEncoding.default)
49
+                                                   "versionnum":"3.6.0"],
50
+                                      encoding: JSONEncoding.default)
50 51
         }
51 52
         
52 53
     }
53 54
     
54 55
     var headers: [String : String]? {
55
-        
56 56
         switch self {
57 57
         case .login(_, _, let showLoading):
58
-            return ["showLoading": "\(showLoading)"]
58
+            
59
+            return [
60
+                "st":"false",
61
+
62
+                "Content-type":"application/json"]
59 63
         default:
60 64
             return nil
61 65
         }
62 66
         
63 67
     }
68
+    
69
+    var sampleData: Data {
70
+            switch self {
71
+            case .login:
72
+                return "should be filled properly".utf8Encoded
73
+            }
74
+        }
75
+}
76
+
77
+private extension String {
78
+    var utf8Encoded:Data {
79
+        return data(using: .utf8)!
80
+    }
64 81
 }

+ 17
- 0
iOSFirst/util/Logger.swift Näytä tiedosto

@@ -0,0 +1,17 @@
1
+//
2
+//  Logger.swift
3
+//  iOSFirst
4
+//
5
+//  Created by 孙宇峰 on 2023/2/22.
6
+//
7
+import SwiftyBeaver
8
+import Foundation
9
+let log: SwiftyBeaver.Type = {
10
+    let log = SwiftyBeaver.self
11
+    
12
+    // add log destinations. at least one is needed!
13
+    let console = ConsoleDestination()  // log to Xcode Console
14
+    log.addDestination(console)
15
+
16
+    return log
17
+}()

Loading…
Peruuta
Tallenna