first

0 parents
Showing 86 changed ファイルs with 14954 additions and 0 deletions
1 *.xcodeproj/*
2 !*.xcodeproj/project.pbxproj
3 !*.xcworkspace/contents.xcworkspacedata
4 .DS_Store
1 // AFHTTPSessionManager.h
2 // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #import <Foundation/Foundation.h>
23 #if !TARGET_OS_WATCH
24 #import <SystemConfiguration/SystemConfiguration.h>
25 #endif
26 #import <TargetConditionals.h>
27
28 #if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV
29 #import <MobileCoreServices/MobileCoreServices.h>
30 #else
31 #import <CoreServices/CoreServices.h>
32 #endif
33
34 #import "AFURLSessionManager.h"
35
36 /**
37 `AFHTTPSessionManager` is a subclass of `AFURLSessionManager` with convenience methods for making HTTP requests. When a `baseURL` is provided, requests made with the `GET` / `POST` / et al. convenience methods can be made with relative paths.
38
39 ## Subclassing Notes
40
41 Developers targeting iOS 7 or Mac OS X 10.9 or later that deal extensively with a web service are encouraged to subclass `AFHTTPSessionManager`, providing a class method that returns a shared singleton object on which authentication and other configuration can be shared across the application.
42
43 For developers targeting iOS 6 or Mac OS X 10.8 or earlier, `AFHTTPRequestOperationManager` may be used to similar effect.
44
45 ## Methods to Override
46
47 To change the behavior of all data task operation construction, which is also used in the `GET` / `POST` / et al. convenience methods, override `dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:`.
48
49 ## Serialization
50
51 Requests created by an HTTP client will contain default headers and encode parameters according to the `requestSerializer` property, which is an object conforming to `<AFURLRequestSerialization>`.
52
53 Responses received from the server are automatically validated and serialized by the `responseSerializers` property, which is an object conforming to `<AFURLResponseSerialization>`
54
55 ## URL Construction Using Relative Paths
56
57 For HTTP convenience methods, the request serializer constructs URLs from the path relative to the `-baseURL`, using `NSURL +URLWithString:relativeToURL:`, when provided. If `baseURL` is `nil`, `path` needs to resolve to a valid `NSURL` object using `NSURL +URLWithString:`.
58
59 Below are a few examples of how `baseURL` and relative paths interact:
60
61 NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"];
62 [NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo
63 [NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz
64 [NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo
65 [NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo
66 [NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/
67 [NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/
68
69 Also important to note is that a trailing slash will be added to any `baseURL` without one. This would otherwise cause unexpected behavior when constructing URLs using paths without a leading slash.
70
71 @warning Managers for background sessions must be owned for the duration of their use. This can be accomplished by creating an application-wide or shared singleton instance.
72 */
73
74 NS_ASSUME_NONNULL_BEGIN
75
76 @interface AFHTTPSessionManager : AFURLSessionManager <NSSecureCoding, NSCopying>
77
78 /**
79 The URL used to construct requests from relative paths in methods like `requestWithMethod:URLString:parameters:`, and the `GET` / `POST` / et al. convenience methods.
80 */
81 @property (readonly, nonatomic, strong, nullable) NSURL *baseURL;
82
83 /**
84 Requests created with `requestWithMethod:URLString:parameters:` & `multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:` are constructed with a set of default headers using a parameter serialization specified by this property. By default, this is set to an instance of `AFHTTPRequestSerializer`, which serializes query string parameters for `GET`, `HEAD`, and `DELETE` requests, or otherwise URL-form-encodes HTTP message bodies.
85
86 @warning `requestSerializer` must not be `nil`.
87 */
88 @property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;
89
90 /**
91 Responses sent from the server in data tasks created with `dataTaskWithRequest:success:failure:` and run using the `GET` / `POST` / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to an instance of `AFJSONResponseSerializer`.
92
93 @warning `responseSerializer` must not be `nil`.
94 */
95 @property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
96
97 ///---------------------
98 /// @name Initialization
99 ///---------------------
100
101 /**
102 Creates and returns an `AFHTTPSessionManager` object.
103 */
104 + (instancetype)manager;
105
106 /**
107 Initializes an `AFHTTPSessionManager` object with the specified base URL.
108
109 @param url The base URL for the HTTP client.
110
111 @return The newly-initialized HTTP client
112 */
113 - (instancetype)initWithBaseURL:(nullable NSURL *)url;
114
115 /**
116 Initializes an `AFHTTPSessionManager` object with the specified base URL.
117
118 This is the designated initializer.
119
120 @param url The base URL for the HTTP client.
121 @param configuration The configuration used to create the managed session.
122
123 @return The newly-initialized HTTP client
124 */
125 - (instancetype)initWithBaseURL:(nullable NSURL *)url
126 sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
127
128 ///---------------------------
129 /// @name Making HTTP Requests
130 ///---------------------------
131
132 /**
133 Creates and runs an `NSURLSessionDataTask` with a `GET` request.
134
135 @param URLString The URL string used to create the request URL.
136 @param parameters The parameters to be encoded according to the client request serializer.
137 @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
138 @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
139
140 @see -dataTaskWithRequest:completionHandler:
141 */
142 - (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
143 parameters:(nullable id)parameters
144 success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
145 failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
146
147
148 /**
149 Creates and runs an `NSURLSessionDataTask` with a `GET` request.
150
151 @param URLString The URL string used to create the request URL.
152 @param parameters The parameters to be encoded according to the client request serializer.
153 @param downloadProgress A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue.
154 @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
155 @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
156
157 @see -dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
158 */
159 - (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
160 parameters:(nullable id)parameters
161 progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
162 success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
163 failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
164
165 /**
166 Creates and runs an `NSURLSessionDataTask` with a `HEAD` request.
167
168 @param URLString The URL string used to create the request URL.
169 @param parameters The parameters to be encoded according to the client request serializer.
170 @param success A block object to be executed when the task finishes successfully. This block has no return value and takes a single arguments: the data task.
171 @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
172
173 @see -dataTaskWithRequest:completionHandler:
174 */
175 - (nullable NSURLSessionDataTask *)HEAD:(NSString *)URLString
176 parameters:(nullable id)parameters
177 success:(nullable void (^)(NSURLSessionDataTask *task))success
178 failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
179
180 /**
181 Creates and runs an `NSURLSessionDataTask` with a `POST` request.
182
183 @param URLString The URL string used to create the request URL.
184 @param parameters The parameters to be encoded according to the client request serializer.
185 @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
186 @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
187
188 @see -dataTaskWithRequest:completionHandler:
189 */
190 - (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
191 parameters:(nullable id)parameters
192 success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
193 failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
194
195 /**
196 Creates and runs an `NSURLSessionDataTask` with a `POST` request.
197
198 @param URLString The URL string used to create the request URL.
199 @param parameters The parameters to be encoded according to the client request serializer.
200 @param uploadProgress A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
201 @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
202 @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
203
204 @see -dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
205 */
206 - (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
207 parameters:(nullable id)parameters
208 progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
209 success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
210 failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
211
212 /**
213 Creates and runs an `NSURLSessionDataTask` with a multipart `POST` request.
214
215 @param URLString The URL string used to create the request URL.
216 @param parameters The parameters to be encoded according to the client request serializer.
217 @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol.
218 @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
219 @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
220
221 @see -dataTaskWithRequest:completionHandler:
222 */
223 - (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
224 parameters:(nullable id)parameters
225 constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
226 success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
227 failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
228
229 /**
230 Creates and runs an `NSURLSessionDataTask` with a multipart `POST` request.
231
232 @param URLString The URL string used to create the request URL.
233 @param parameters The parameters to be encoded according to the client request serializer.
234 @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol.
235 @param uploadProgress A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
236 @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
237 @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
238
239 @see -dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
240 */
241 - (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
242 parameters:(nullable id)parameters
243 constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
244 progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
245 success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
246 failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
247
248 /**
249 Creates and runs an `NSURLSessionDataTask` with a `PUT` request.
250
251 @param URLString The URL string used to create the request URL.
252 @param parameters The parameters to be encoded according to the client request serializer.
253 @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
254 @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
255
256 @see -dataTaskWithRequest:completionHandler:
257 */
258 - (nullable NSURLSessionDataTask *)PUT:(NSString *)URLString
259 parameters:(nullable id)parameters
260 success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
261 failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
262
263 /**
264 Creates and runs an `NSURLSessionDataTask` with a `PATCH` request.
265
266 @param URLString The URL string used to create the request URL.
267 @param parameters The parameters to be encoded according to the client request serializer.
268 @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
269 @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
270
271 @see -dataTaskWithRequest:completionHandler:
272 */
273 - (nullable NSURLSessionDataTask *)PATCH:(NSString *)URLString
274 parameters:(nullable id)parameters
275 success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
276 failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
277
278 /**
279 Creates and runs an `NSURLSessionDataTask` with a `DELETE` request.
280
281 @param URLString The URL string used to create the request URL.
282 @param parameters The parameters to be encoded according to the client request serializer.
283 @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
284 @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
285
286 @see -dataTaskWithRequest:completionHandler:
287 */
288 - (nullable NSURLSessionDataTask *)DELETE:(NSString *)URLString
289 parameters:(nullable id)parameters
290 success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
291 failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
292
293 @end
294
295 NS_ASSUME_NONNULL_END
1 // AFHTTPSessionManager.m
2 // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #import "AFHTTPSessionManager.h"
23
24 #import "AFURLRequestSerialization.h"
25 #import "AFURLResponseSerialization.h"
26
27 #import <Availability.h>
28 #import <TargetConditionals.h>
29 #import <Security/Security.h>
30
31 #import <netinet/in.h>
32 #import <netinet6/in6.h>
33 #import <arpa/inet.h>
34 #import <ifaddrs.h>
35 #import <netdb.h>
36
37 #if TARGET_OS_IOS || TARGET_OS_TV
38 #import <UIKit/UIKit.h>
39 #elif TARGET_OS_WATCH
40 #import <WatchKit/WatchKit.h>
41 #endif
42
43 @interface AFHTTPSessionManager ()
44 @property (readwrite, nonatomic, strong) NSURL *baseURL;
45 @end
46
47 @implementation AFHTTPSessionManager
48 @dynamic responseSerializer;
49
50 + (instancetype)manager {
51 return [[[self class] alloc] initWithBaseURL:nil];
52 }
53
54 - (instancetype)init {
55 return [self initWithBaseURL:nil];
56 }
57
58 - (instancetype)initWithBaseURL:(NSURL *)url {
59 return [self initWithBaseURL:url sessionConfiguration:nil];
60 }
61
62 - (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
63 return [self initWithBaseURL:nil sessionConfiguration:configuration];
64 }
65
66 - (instancetype)initWithBaseURL:(NSURL *)url
67 sessionConfiguration:(NSURLSessionConfiguration *)configuration
68 {
69 self = [super initWithSessionConfiguration:configuration];
70 if (!self) {
71 return nil;
72 }
73
74 // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
75 if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
76 url = [url URLByAppendingPathComponent:@""];
77 }
78
79 self.baseURL = url;
80
81 self.requestSerializer = [AFHTTPRequestSerializer serializer];
82 self.responseSerializer = [AFJSONResponseSerializer serializer];
83
84 return self;
85 }
86
87 #pragma mark -
88
89 - (void)setRequestSerializer:(AFHTTPRequestSerializer <AFURLRequestSerialization> *)requestSerializer {
90 NSParameterAssert(requestSerializer);
91
92 _requestSerializer = requestSerializer;
93 }
94
95 - (void)setResponseSerializer:(AFHTTPResponseSerializer <AFURLResponseSerialization> *)responseSerializer {
96 NSParameterAssert(responseSerializer);
97
98 [super setResponseSerializer:responseSerializer];
99 }
100
101 #pragma mark -
102
103 - (NSURLSessionDataTask *)GET:(NSString *)URLString
104 parameters:(id)parameters
105 success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
106 failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
107 {
108
109 return [self GET:URLString parameters:parameters progress:nil success:success failure:failure];
110 }
111
112 - (NSURLSessionDataTask *)GET:(NSString *)URLString
113 parameters:(id)parameters
114 progress:(void (^)(NSProgress * _Nonnull))downloadProgress
115 success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
116 failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
117 {
118
119 NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
120 URLString:URLString
121 parameters:parameters
122 uploadProgress:nil
123 downloadProgress:downloadProgress
124 success:success
125 failure:failure];
126
127 [dataTask resume];
128
129 return dataTask;
130 }
131
132 - (NSURLSessionDataTask *)HEAD:(NSString *)URLString
133 parameters:(id)parameters
134 success:(void (^)(NSURLSessionDataTask *task))success
135 failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
136 {
137 NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"HEAD" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:^(NSURLSessionDataTask *task, __unused id responseObject) {
138 if (success) {
139 success(task);
140 }
141 } failure:failure];
142
143 [dataTask resume];
144
145 return dataTask;
146 }
147
148 - (NSURLSessionDataTask *)POST:(NSString *)URLString
149 parameters:(id)parameters
150 success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
151 failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
152 {
153 return [self POST:URLString parameters:parameters progress:nil success:success failure:failure];
154 }
155
156 - (NSURLSessionDataTask *)POST:(NSString *)URLString
157 parameters:(id)parameters
158 progress:(void (^)(NSProgress * _Nonnull))uploadProgress
159 success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
160 failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
161 {
162 NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure];
163
164 [dataTask resume];
165
166 return dataTask;
167 }
168
169 - (NSURLSessionDataTask *)POST:(NSString *)URLString
170 parameters:(nullable id)parameters
171 constructingBodyWithBlock:(nullable void (^)(id<AFMultipartFormData> _Nonnull))block
172 success:(nullable void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
173 failure:(nullable void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
174 {
175 return [self POST:URLString parameters:parameters constructingBodyWithBlock:block progress:nil success:success failure:failure];
176 }
177
178 - (NSURLSessionDataTask *)POST:(NSString *)URLString
179 parameters:(id)parameters
180 constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
181 progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
182 success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
183 failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
184 {
185 NSError *serializationError = nil;
186 NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
187 if (serializationError) {
188 if (failure) {
189 dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
190 failure(nil, serializationError);
191 });
192 }
193
194 return nil;
195 }
196
197 __block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:uploadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
198 if (error) {
199 if (failure) {
200 failure(task, error);
201 }
202 } else {
203 if (success) {
204 success(task, responseObject);
205 }
206 }
207 }];
208
209 [task resume];
210
211 return task;
212 }
213
214 - (NSURLSessionDataTask *)PUT:(NSString *)URLString
215 parameters:(id)parameters
216 success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
217 failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
218 {
219 NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PUT" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:success failure:failure];
220
221 [dataTask resume];
222
223 return dataTask;
224 }
225
226 - (NSURLSessionDataTask *)PATCH:(NSString *)URLString
227 parameters:(id)parameters
228 success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
229 failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
230 {
231 NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PATCH" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:success failure:failure];
232
233 [dataTask resume];
234
235 return dataTask;
236 }
237
238 - (NSURLSessionDataTask *)DELETE:(NSString *)URLString
239 parameters:(id)parameters
240 success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
241 failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
242 {
243 NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"DELETE" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:success failure:failure];
244
245 [dataTask resume];
246
247 return dataTask;
248 }
249
250 - (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
251 URLString:(NSString *)URLString
252 parameters:(id)parameters
253 uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
254 downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
255 success:(void (^)(NSURLSessionDataTask *, id))success
256 failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
257 {
258 NSError *serializationError = nil;
259 NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
260 if (serializationError) {
261 if (failure) {
262 dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
263 failure(nil, serializationError);
264 });
265 }
266
267 return nil;
268 }
269
270 __block NSURLSessionDataTask *dataTask = nil;
271 dataTask = [self dataTaskWithRequest:request
272 uploadProgress:uploadProgress
273 downloadProgress:downloadProgress
274 completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
275 if (error) {
276 if (failure) {
277 failure(dataTask, error);
278 }
279 } else {
280 if (success) {
281 success(dataTask, responseObject);
282 }
283 }
284 }];
285
286 return dataTask;
287 }
288
289 #pragma mark - NSObject
290
291 - (NSString *)description {
292 return [NSString stringWithFormat:@"<%@: %p, baseURL: %@, session: %@, operationQueue: %@>", NSStringFromClass([self class]), self, [self.baseURL absoluteString], self.session, self.operationQueue];
293 }
294
295 #pragma mark - NSSecureCoding
296
297 + (BOOL)supportsSecureCoding {
298 return YES;
299 }
300
301 - (instancetype)initWithCoder:(NSCoder *)decoder {
302 NSURL *baseURL = [decoder decodeObjectOfClass:[NSURL class] forKey:NSStringFromSelector(@selector(baseURL))];
303 NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"];
304 if (!configuration) {
305 NSString *configurationIdentifier = [decoder decodeObjectOfClass:[NSString class] forKey:@"identifier"];
306 if (configurationIdentifier) {
307 #if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1100)
308 configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:configurationIdentifier];
309 #else
310 configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:configurationIdentifier];
311 #endif
312 }
313 }
314
315 self = [self initWithBaseURL:baseURL sessionConfiguration:configuration];
316 if (!self) {
317 return nil;
318 }
319
320 self.requestSerializer = [decoder decodeObjectOfClass:[AFHTTPRequestSerializer class] forKey:NSStringFromSelector(@selector(requestSerializer))];
321 self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))];
322 AFSecurityPolicy *decodedPolicy = [decoder decodeObjectOfClass:[AFSecurityPolicy class] forKey:NSStringFromSelector(@selector(securityPolicy))];
323 if (decodedPolicy) {
324 self.securityPolicy = decodedPolicy;
325 }
326
327 return self;
328 }
329
330 - (void)encodeWithCoder:(NSCoder *)coder {
331 [super encodeWithCoder:coder];
332
333 [coder encodeObject:self.baseURL forKey:NSStringFromSelector(@selector(baseURL))];
334 if ([self.session.configuration conformsToProtocol:@protocol(NSCoding)]) {
335 [coder encodeObject:self.session.configuration forKey:@"sessionConfiguration"];
336 } else {
337 [coder encodeObject:self.session.configuration.identifier forKey:@"identifier"];
338 }
339 [coder encodeObject:self.requestSerializer forKey:NSStringFromSelector(@selector(requestSerializer))];
340 [coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))];
341 [coder encodeObject:self.securityPolicy forKey:NSStringFromSelector(@selector(securityPolicy))];
342 }
343
344 #pragma mark - NSCopying
345
346 - (instancetype)copyWithZone:(NSZone *)zone {
347 AFHTTPSessionManager *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL sessionConfiguration:self.session.configuration];
348
349 HTTPClient.requestSerializer = [self.requestSerializer copyWithZone:zone];
350 HTTPClient.responseSerializer = [self.responseSerializer copyWithZone:zone];
351 HTTPClient.securityPolicy = [self.securityPolicy copyWithZone:zone];
352 return HTTPClient;
353 }
354
355 @end
1 // AFNetworkReachabilityManager.h
2 // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #import <Foundation/Foundation.h>
23
24 #if !TARGET_OS_WATCH
25 #import <SystemConfiguration/SystemConfiguration.h>
26
27 typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
28 AFNetworkReachabilityStatusUnknown = -1,
29 AFNetworkReachabilityStatusNotReachable = 0,
30 AFNetworkReachabilityStatusReachableViaWWAN = 1,
31 AFNetworkReachabilityStatusReachableViaWiFi = 2,
32 };
33
34 NS_ASSUME_NONNULL_BEGIN
35
36 /**
37 `AFNetworkReachabilityManager` monitors the reachability of domains, and addresses for both WWAN and WiFi network interfaces.
38
39 Reachability can be used to determine background information about why a network operation failed, or to trigger a network operation retrying when a connection is established. It should not be used to prevent a user from initiating a network request, as it's possible that an initial request may be required to establish reachability.
40
41 See Apple's Reachability Sample Code ( https://developer.apple.com/library/ios/samplecode/reachability/ )
42
43 @warning Instances of `AFNetworkReachabilityManager` must be started with `-startMonitoring` before reachability status can be determined.
44 */
45 @interface AFNetworkReachabilityManager : NSObject
46
47 /**
48 The current network reachability status.
49 */
50 @property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
51
52 /**
53 Whether or not the network is currently reachable.
54 */
55 @property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable;
56
57 /**
58 Whether or not the network is currently reachable via WWAN.
59 */
60 @property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN;
61
62 /**
63 Whether or not the network is currently reachable via WiFi.
64 */
65 @property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi;
66
67 ///---------------------
68 /// @name Initialization
69 ///---------------------
70
71 /**
72 Returns the shared network reachability manager.
73 */
74 + (instancetype)sharedManager;
75
76 /**
77 Creates and returns a network reachability manager with the default socket address.
78
79 @return An initialized network reachability manager, actively monitoring the default socket address.
80 */
81 + (instancetype)manager;
82
83 /**
84 Creates and returns a network reachability manager for the specified domain.
85
86 @param domain The domain used to evaluate network reachability.
87
88 @return An initialized network reachability manager, actively monitoring the specified domain.
89 */
90 + (instancetype)managerForDomain:(NSString *)domain;
91
92 /**
93 Creates and returns a network reachability manager for the socket address.
94
95 @param address The socket address (`sockaddr_in6`) used to evaluate network reachability.
96
97 @return An initialized network reachability manager, actively monitoring the specified socket address.
98 */
99 + (instancetype)managerForAddress:(const void *)address;
100
101 /**
102 Initializes an instance of a network reachability manager from the specified reachability object.
103
104 @param reachability The reachability object to monitor.
105
106 @return An initialized network reachability manager, actively monitoring the specified reachability.
107 */
108 - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;
109
110 ///--------------------------------------------------
111 /// @name Starting & Stopping Reachability Monitoring
112 ///--------------------------------------------------
113
114 /**
115 Starts monitoring for changes in network reachability status.
116 */
117 - (void)startMonitoring;
118
119 /**
120 Stops monitoring for changes in network reachability status.
121 */
122 - (void)stopMonitoring;
123
124 ///-------------------------------------------------
125 /// @name Getting Localized Reachability Description
126 ///-------------------------------------------------
127
128 /**
129 Returns a localized string representation of the current network reachability status.
130 */
131 - (NSString *)localizedNetworkReachabilityStatusString;
132
133 ///---------------------------------------------------
134 /// @name Setting Network Reachability Change Callback
135 ///---------------------------------------------------
136
137 /**
138 Sets a callback to be executed when the network availability of the `baseURL` host changes.
139
140 @param block A block object to be executed when the network availability of the `baseURL` host changes.. This block has no return value and takes a single argument which represents the various reachability states from the device to the `baseURL`.
141 */
142 - (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block;
143
144 @end
145
146 ///----------------
147 /// @name Constants
148 ///----------------
149
150 /**
151 ## Network Reachability
152
153 The following constants are provided by `AFNetworkReachabilityManager` as possible network reachability statuses.
154
155 enum {
156 AFNetworkReachabilityStatusUnknown,
157 AFNetworkReachabilityStatusNotReachable,
158 AFNetworkReachabilityStatusReachableViaWWAN,
159 AFNetworkReachabilityStatusReachableViaWiFi,
160 }
161
162 `AFNetworkReachabilityStatusUnknown`
163 The `baseURL` host reachability is not known.
164
165 `AFNetworkReachabilityStatusNotReachable`
166 The `baseURL` host cannot be reached.
167
168 `AFNetworkReachabilityStatusReachableViaWWAN`
169 The `baseURL` host can be reached via a cellular connection, such as EDGE or GPRS.
170
171 `AFNetworkReachabilityStatusReachableViaWiFi`
172 The `baseURL` host can be reached via a Wi-Fi connection.
173
174 ### Keys for Notification UserInfo Dictionary
175
176 Strings that are used as keys in a `userInfo` dictionary in a network reachability status change notification.
177
178 `AFNetworkingReachabilityNotificationStatusItem`
179 A key in the userInfo dictionary in a `AFNetworkingReachabilityDidChangeNotification` notification.
180 The corresponding value is an `NSNumber` object representing the `AFNetworkReachabilityStatus` value for the current reachability status.
181 */
182
183 ///--------------------
184 /// @name Notifications
185 ///--------------------
186
187 /**
188 Posted when network reachability changes.
189 This notification assigns no notification object. The `userInfo` dictionary contains an `NSNumber` object under the `AFNetworkingReachabilityNotificationStatusItem` key, representing the `AFNetworkReachabilityStatus` value for the current network reachability.
190
191 @warning In order for network reachability to be monitored, include the `SystemConfiguration` framework in the active target's "Link Binary With Library" build phase, and add `#import <SystemConfiguration/SystemConfiguration.h>` to the header prefix of the project (`Prefix.pch`).
192 */
193 FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityDidChangeNotification;
194 FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityNotificationStatusItem;
195
196 ///--------------------
197 /// @name Functions
198 ///--------------------
199
200 /**
201 Returns a localized string representation of an `AFNetworkReachabilityStatus` value.
202 */
203 FOUNDATION_EXPORT NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status);
204
205 NS_ASSUME_NONNULL_END
206 #endif
1 // AFNetworkReachabilityManager.m
2 // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #import "AFNetworkReachabilityManager.h"
23 #if !TARGET_OS_WATCH
24
25 #import <netinet/in.h>
26 #import <netinet6/in6.h>
27 #import <arpa/inet.h>
28 #import <ifaddrs.h>
29 #import <netdb.h>
30
31 NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change";
32 NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem";
33
34 typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status);
35
36 NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status) {
37 switch (status) {
38 case AFNetworkReachabilityStatusNotReachable:
39 return NSLocalizedStringFromTable(@"Not Reachable", @"AFNetworking", nil);
40 case AFNetworkReachabilityStatusReachableViaWWAN:
41 return NSLocalizedStringFromTable(@"Reachable via WWAN", @"AFNetworking", nil);
42 case AFNetworkReachabilityStatusReachableViaWiFi:
43 return NSLocalizedStringFromTable(@"Reachable via WiFi", @"AFNetworking", nil);
44 case AFNetworkReachabilityStatusUnknown:
45 default:
46 return NSLocalizedStringFromTable(@"Unknown", @"AFNetworking", nil);
47 }
48 }
49
50 static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) {
51 BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0);
52 BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0);
53 BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0));
54 BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0);
55 BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction));
56
57 AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown;
58 if (isNetworkReachable == NO) {
59 status = AFNetworkReachabilityStatusNotReachable;
60 }
61 #if TARGET_OS_IPHONE
62 else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) {
63 status = AFNetworkReachabilityStatusReachableViaWWAN;
64 }
65 #endif
66 else {
67 status = AFNetworkReachabilityStatusReachableViaWiFi;
68 }
69
70 return status;
71 }
72
73 /**
74 * Queue a status change notification for the main thread.
75 *
76 * This is done to ensure that the notifications are received in the same order
77 * as they are sent. If notifications are sent directly, it is possible that
78 * a queued notification (for an earlier status condition) is processed after
79 * the later update, resulting in the listener being left in the wrong state.
80 */
81 static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {
82 AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
83 dispatch_async(dispatch_get_main_queue(), ^{
84 if (block) {
85 block(status);
86 }
87 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
88 NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) };
89 [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:userInfo];
90 });
91 }
92
93 static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
94 AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);
95 }
96
97
98 static const void * AFNetworkReachabilityRetainCallback(const void *info) {
99 return Block_copy(info);
100 }
101
102 static void AFNetworkReachabilityReleaseCallback(const void *info) {
103 if (info) {
104 Block_release(info);
105 }
106 }
107
108 @interface AFNetworkReachabilityManager ()
109 @property (readonly, nonatomic, assign) SCNetworkReachabilityRef networkReachability;
110 @property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
111 @property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock;
112 @end
113
114 @implementation AFNetworkReachabilityManager
115
116 + (instancetype)sharedManager {
117 static AFNetworkReachabilityManager *_sharedManager = nil;
118 static dispatch_once_t onceToken;
119 dispatch_once(&onceToken, ^{
120 _sharedManager = [self manager];
121 });
122
123 return _sharedManager;
124 }
125
126 + (instancetype)managerForDomain:(NSString *)domain {
127 SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
128
129 AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
130
131 CFRelease(reachability);
132
133 return manager;
134 }
135
136 + (instancetype)managerForAddress:(const void *)address {
137 SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
138 AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
139
140 CFRelease(reachability);
141
142 return manager;
143 }
144
145 + (instancetype)manager
146 {
147 #if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
148 struct sockaddr_in6 address;
149 bzero(&address, sizeof(address));
150 address.sin6_len = sizeof(address);
151 address.sin6_family = AF_INET6;
152 #else
153 struct sockaddr_in address;
154 bzero(&address, sizeof(address));
155 address.sin_len = sizeof(address);
156 address.sin_family = AF_INET;
157 #endif
158 return [self managerForAddress:&address];
159 }
160
161 - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
162 self = [super init];
163 if (!self) {
164 return nil;
165 }
166
167 _networkReachability = CFRetain(reachability);
168 self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;
169
170 return self;
171 }
172
173 - (instancetype)init NS_UNAVAILABLE
174 {
175 return nil;
176 }
177
178 - (void)dealloc {
179 [self stopMonitoring];
180
181 if (_networkReachability != NULL) {
182 CFRelease(_networkReachability);
183 }
184 }
185
186 #pragma mark -
187
188 - (BOOL)isReachable {
189 return [self isReachableViaWWAN] || [self isReachableViaWiFi];
190 }
191
192 - (BOOL)isReachableViaWWAN {
193 return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN;
194 }
195
196 - (BOOL)isReachableViaWiFi {
197 return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi;
198 }
199
200 #pragma mark -
201
202 - (void)startMonitoring {
203 [self stopMonitoring];
204
205 if (!self.networkReachability) {
206 return;
207 }
208
209 __weak __typeof(self)weakSelf = self;
210 AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
211 __strong __typeof(weakSelf)strongSelf = weakSelf;
212
213 strongSelf.networkReachabilityStatus = status;
214 if (strongSelf.networkReachabilityStatusBlock) {
215 strongSelf.networkReachabilityStatusBlock(status);
216 }
217
218 };
219
220 SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
221 SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
222 SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
223
224 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
225 SCNetworkReachabilityFlags flags;
226 if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
227 AFPostReachabilityStatusChange(flags, callback);
228 }
229 });
230 }
231
232 - (void)stopMonitoring {
233 if (!self.networkReachability) {
234 return;
235 }
236
237 SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
238 }
239
240 #pragma mark -
241
242 - (NSString *)localizedNetworkReachabilityStatusString {
243 return AFStringFromNetworkReachabilityStatus(self.networkReachabilityStatus);
244 }
245
246 #pragma mark -
247
248 - (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
249 self.networkReachabilityStatusBlock = block;
250 }
251
252 #pragma mark - NSKeyValueObserving
253
254 + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
255 if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) {
256 return [NSSet setWithObject:@"networkReachabilityStatus"];
257 }
258
259 return [super keyPathsForValuesAffectingValueForKey:key];
260 }
261
262 @end
263 #endif
1 // AFNetworking.h
2 //
3 // Copyright (c) 2013 AFNetworking (http://afnetworking.com/)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22
23 #import <Foundation/Foundation.h>
24 #import <Availability.h>
25 #import <TargetConditionals.h>
26
27 #ifndef _AFNETWORKING_
28 #define _AFNETWORKING_
29
30 #import "AFURLRequestSerialization.h"
31 #import "AFURLResponseSerialization.h"
32 #import "AFSecurityPolicy.h"
33
34 #if !TARGET_OS_WATCH
35 #import "AFNetworkReachabilityManager.h"
36 #endif
37
38 #import "AFURLSessionManager.h"
39 #import "AFHTTPSessionManager.h"
40
41 #endif /* _AFNETWORKING_ */
1 // AFSecurityPolicy.h
2 // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #import <Foundation/Foundation.h>
23 #import <Security/Security.h>
24
25 typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
26 AFSSLPinningModeNone,
27 AFSSLPinningModePublicKey,
28 AFSSLPinningModeCertificate,
29 };
30
31 /**
32 `AFSecurityPolicy` evaluates server trust against pinned X.509 certificates and public keys over secure connections.
33
34 Adding pinned SSL certificates to your app helps prevent man-in-the-middle attacks and other vulnerabilities. Applications dealing with sensitive customer data or financial information are strongly encouraged to route all communication over an HTTPS connection with SSL pinning configured and enabled.
35 */
36
37 NS_ASSUME_NONNULL_BEGIN
38
39 @interface AFSecurityPolicy : NSObject <NSSecureCoding, NSCopying>
40
41 /**
42 The criteria by which server trust should be evaluated against the pinned SSL certificates. Defaults to `AFSSLPinningModeNone`.
43 */
44 @property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
45
46 /**
47 The certificates used to evaluate server trust according to the SSL pinning mode.
48
49 By default, this property is set to any (`.cer`) certificates included in the target compiling AFNetworking. Note that if you are using AFNetworking as embedded framework, no certificates will be pinned by default. Use `certificatesInBundle` to load certificates from your target, and then create a new policy by calling `policyWithPinningMode:withPinnedCertificates`.
50
51 Note that if pinning is enabled, `evaluateServerTrust:forDomain:` will return true if any pinned certificate matches.
52 */
53 @property (nonatomic, strong, nullable) NSSet <NSData *> *pinnedCertificates;
54
55 /**
56 Whether or not to trust servers with an invalid or expired SSL certificates. Defaults to `NO`.
57 */
58 @property (nonatomic, assign) BOOL allowInvalidCertificates;
59
60 /**
61 Whether or not to validate the domain name in the certificate's CN field. Defaults to `YES`.
62 */
63 @property (nonatomic, assign) BOOL validatesDomainName;
64
65 ///-----------------------------------------
66 /// @name Getting Certificates from the Bundle
67 ///-----------------------------------------
68
69 /**
70 Returns any certificates included in the bundle. If you are using AFNetworking as an embedded framework, you must use this method to find the certificates you have included in your app bundle, and use them when creating your security policy by calling `policyWithPinningMode:withPinnedCertificates`.
71
72 @return The certificates included in the given bundle.
73 */
74 + (NSSet <NSData *> *)certificatesInBundle:(NSBundle *)bundle;
75
76 ///-----------------------------------------
77 /// @name Getting Specific Security Policies
78 ///-----------------------------------------
79
80 /**
81 Returns the shared default security policy, which does not allow invalid certificates, validates domain name, and does not validate against pinned certificates or public keys.
82
83 @return The default security policy.
84 */
85 + (instancetype)defaultPolicy;
86
87 ///---------------------
88 /// @name Initialization
89 ///---------------------
90
91 /**
92 Creates and returns a security policy with the specified pinning mode.
93
94 @param pinningMode The SSL pinning mode.
95
96 @return A new security policy.
97 */
98 + (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode;
99
100 /**
101 Creates and returns a security policy with the specified pinning mode.
102
103 @param pinningMode The SSL pinning mode.
104 @param pinnedCertificates The certificates to pin against.
105
106 @return A new security policy.
107 */
108 + (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet <NSData *> *)pinnedCertificates;
109
110 ///------------------------------
111 /// @name Evaluating Server Trust
112 ///------------------------------
113
114 /**
115 Whether or not the specified server trust should be accepted, based on the security policy.
116
117 This method should be used when responding to an authentication challenge from a server.
118
119 @param serverTrust The X.509 certificate trust of the server.
120 @param domain The domain of serverTrust. If `nil`, the domain will not be validated.
121
122 @return Whether or not to trust the server.
123 */
124 - (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
125 forDomain:(nullable NSString *)domain;
126
127 @end
128
129 NS_ASSUME_NONNULL_END
130
131 ///----------------
132 /// @name Constants
133 ///----------------
134
135 /**
136 ## SSL Pinning Modes
137
138 The following constants are provided by `AFSSLPinningMode` as possible SSL pinning modes.
139
140 enum {
141 AFSSLPinningModeNone,
142 AFSSLPinningModePublicKey,
143 AFSSLPinningModeCertificate,
144 }
145
146 `AFSSLPinningModeNone`
147 Do not used pinned certificates to validate servers.
148
149 `AFSSLPinningModePublicKey`
150 Validate host certificates against public keys of pinned certificates.
151
152 `AFSSLPinningModeCertificate`
153 Validate host certificates against pinned certificates.
154 */
1 // AFSecurityPolicy.m
2 // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #import "AFSecurityPolicy.h"
23
24 #import <AssertMacros.h>
25
26 #if !TARGET_OS_IOS && !TARGET_OS_WATCH && !TARGET_OS_TV
27 static NSData * AFSecKeyGetData(SecKeyRef key) {
28 CFDataRef data = NULL;
29
30 __Require_noErr_Quiet(SecItemExport(key, kSecFormatUnknown, kSecItemPemArmour, NULL, &data), _out);
31
32 return (__bridge_transfer NSData *)data;
33
34 _out:
35 if (data) {
36 CFRelease(data);
37 }
38
39 return nil;
40 }
41 #endif
42
43 static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) {
44 #if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV
45 return [(__bridge id)key1 isEqual:(__bridge id)key2];
46 #else
47 return [AFSecKeyGetData(key1) isEqual:AFSecKeyGetData(key2)];
48 #endif
49 }
50
51 static id AFPublicKeyForCertificate(NSData *certificate) {
52 id allowedPublicKey = nil;
53 SecCertificateRef allowedCertificate;
54 SecCertificateRef allowedCertificates[1];
55 CFArrayRef tempCertificates = nil;
56 SecPolicyRef policy = nil;
57 SecTrustRef allowedTrust = nil;
58 SecTrustResultType result;
59
60 allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);
61 __Require_Quiet(allowedCertificate != NULL, _out);
62
63 allowedCertificates[0] = allowedCertificate;
64 tempCertificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL);
65
66 policy = SecPolicyCreateBasicX509();
67 __Require_noErr_Quiet(SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust), _out);
68 __Require_noErr_Quiet(SecTrustEvaluate(allowedTrust, &result), _out);
69
70 allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust);
71
72 _out:
73 if (allowedTrust) {
74 CFRelease(allowedTrust);
75 }
76
77 if (policy) {
78 CFRelease(policy);
79 }
80
81 if (tempCertificates) {
82 CFRelease(tempCertificates);
83 }
84
85 if (allowedCertificate) {
86 CFRelease(allowedCertificate);
87 }
88
89 return allowedPublicKey;
90 }
91
92 static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) {
93 BOOL isValid = NO;
94 SecTrustResultType result;
95 __Require_noErr_Quiet(SecTrustEvaluate(serverTrust, &result), _out);
96
97 isValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
98
99 _out:
100 return isValid;
101 }
102
103 static NSArray * AFCertificateTrustChainForServerTrust(SecTrustRef serverTrust) {
104 CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);
105 NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount];
106
107 for (CFIndex i = 0; i < certificateCount; i++) {
108 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);
109 [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)];
110 }
111
112 return [NSArray arrayWithArray:trustChain];
113 }
114
115 static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
116 SecPolicyRef policy = SecPolicyCreateBasicX509();
117 CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);
118 NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount];
119 for (CFIndex i = 0; i < certificateCount; i++) {
120 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);
121
122 SecCertificateRef someCertificates[] = {certificate};
123 CFArrayRef certificates = CFArrayCreate(NULL, (const void **)someCertificates, 1, NULL);
124
125 SecTrustRef trust;
126 __Require_noErr_Quiet(SecTrustCreateWithCertificates(certificates, policy, &trust), _out);
127
128 SecTrustResultType result;
129 __Require_noErr_Quiet(SecTrustEvaluate(trust, &result), _out);
130
131 [trustChain addObject:(__bridge_transfer id)SecTrustCopyPublicKey(trust)];
132
133 _out:
134 if (trust) {
135 CFRelease(trust);
136 }
137
138 if (certificates) {
139 CFRelease(certificates);
140 }
141
142 continue;
143 }
144 CFRelease(policy);
145
146 return [NSArray arrayWithArray:trustChain];
147 }
148
149 #pragma mark -
150
151 @interface AFSecurityPolicy()
152 @property (readwrite, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
153 @property (readwrite, nonatomic, strong) NSSet *pinnedPublicKeys;
154 @end
155
156 @implementation AFSecurityPolicy
157
158 + (NSSet *)certificatesInBundle:(NSBundle *)bundle {
159 NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];
160
161 NSMutableSet *certificates = [NSMutableSet setWithCapacity:[paths count]];
162 for (NSString *path in paths) {
163 NSData *certificateData = [NSData dataWithContentsOfFile:path];
164 [certificates addObject:certificateData];
165 }
166
167 return [NSSet setWithSet:certificates];
168 }
169
170 + (NSSet *)defaultPinnedCertificates {
171 static NSSet *_defaultPinnedCertificates = nil;
172 static dispatch_once_t onceToken;
173 dispatch_once(&onceToken, ^{
174 NSBundle *bundle = [NSBundle bundleForClass:[self class]];
175 _defaultPinnedCertificates = [self certificatesInBundle:bundle];
176 });
177
178 return _defaultPinnedCertificates;
179 }
180
181 + (instancetype)defaultPolicy {
182 AFSecurityPolicy *securityPolicy = [[self alloc] init];
183 securityPolicy.SSLPinningMode = AFSSLPinningModeNone;
184
185 return securityPolicy;
186 }
187
188 + (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode {
189 return [self policyWithPinningMode:pinningMode withPinnedCertificates:[self defaultPinnedCertificates]];
190 }
191
192 + (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet *)pinnedCertificates {
193 AFSecurityPolicy *securityPolicy = [[self alloc] init];
194 securityPolicy.SSLPinningMode = pinningMode;
195
196 [securityPolicy setPinnedCertificates:pinnedCertificates];
197
198 return securityPolicy;
199 }
200
201 - (instancetype)init {
202 self = [super init];
203 if (!self) {
204 return nil;
205 }
206
207 self.validatesDomainName = YES;
208
209 return self;
210 }
211
212 - (void)setPinnedCertificates:(NSSet *)pinnedCertificates {
213 _pinnedCertificates = pinnedCertificates;
214
215 if (self.pinnedCertificates) {
216 NSMutableSet *mutablePinnedPublicKeys = [NSMutableSet setWithCapacity:[self.pinnedCertificates count]];
217 for (NSData *certificate in self.pinnedCertificates) {
218 id publicKey = AFPublicKeyForCertificate(certificate);
219 if (!publicKey) {
220 continue;
221 }
222 [mutablePinnedPublicKeys addObject:publicKey];
223 }
224 self.pinnedPublicKeys = [NSSet setWithSet:mutablePinnedPublicKeys];
225 } else {
226 self.pinnedPublicKeys = nil;
227 }
228 }
229
230 #pragma mark -
231
232 - (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
233 forDomain:(NSString *)domain
234 {
235 if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) {
236 // https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html
237 // According to the docs, you should only trust your provided certs for evaluation.
238 // Pinned certificates are added to the trust. Without pinned certificates,
239 // there is nothing to evaluate against.
240 //
241 // From Apple Docs:
242 // "Do not implicitly trust self-signed certificates as anchors (kSecTrustOptionImplicitAnchors).
243 // Instead, add your own (self-signed) CA certificate to the list of trusted anchors."
244 NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");
245 return NO;
246 }
247
248 NSMutableArray *policies = [NSMutableArray array];
249 if (self.validatesDomainName) {
250 [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
251 } else {
252 [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
253 }
254
255 SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
256
257 if (self.SSLPinningMode == AFSSLPinningModeNone) {
258 return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
259 } else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
260 return NO;
261 }
262
263 switch (self.SSLPinningMode) {
264 case AFSSLPinningModeNone:
265 default:
266 return NO;
267 case AFSSLPinningModeCertificate: {
268 NSMutableArray *pinnedCertificates = [NSMutableArray array];
269 for (NSData *certificateData in self.pinnedCertificates) {
270 [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
271 }
272 SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
273
274 if (!AFServerTrustIsValid(serverTrust)) {
275 return NO;
276 }
277
278 // obtain the chain after being validated, which *should* contain the pinned certificate in the last position (if it's the Root CA)
279 NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
280
281 for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
282 if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
283 return YES;
284 }
285 }
286
287 return NO;
288 }
289 case AFSSLPinningModePublicKey: {
290 NSUInteger trustedPublicKeyCount = 0;
291 NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);
292
293 for (id trustChainPublicKey in publicKeys) {
294 for (id pinnedPublicKey in self.pinnedPublicKeys) {
295 if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) {
296 trustedPublicKeyCount += 1;
297 }
298 }
299 }
300 return trustedPublicKeyCount > 0;
301 }
302 }
303
304 return NO;
305 }
306
307 #pragma mark - NSKeyValueObserving
308
309 + (NSSet *)keyPathsForValuesAffectingPinnedPublicKeys {
310 return [NSSet setWithObject:@"pinnedCertificates"];
311 }
312
313 #pragma mark - NSSecureCoding
314
315 + (BOOL)supportsSecureCoding {
316 return YES;
317 }
318
319 - (instancetype)initWithCoder:(NSCoder *)decoder {
320
321 self = [self init];
322 if (!self) {
323 return nil;
324 }
325
326 self.SSLPinningMode = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(SSLPinningMode))] unsignedIntegerValue];
327 self.allowInvalidCertificates = [decoder decodeBoolForKey:NSStringFromSelector(@selector(allowInvalidCertificates))];
328 self.validatesDomainName = [decoder decodeBoolForKey:NSStringFromSelector(@selector(validatesDomainName))];
329 self.pinnedCertificates = [decoder decodeObjectOfClass:[NSArray class] forKey:NSStringFromSelector(@selector(pinnedCertificates))];
330
331 return self;
332 }
333
334 - (void)encodeWithCoder:(NSCoder *)coder {
335 [coder encodeObject:[NSNumber numberWithUnsignedInteger:self.SSLPinningMode] forKey:NSStringFromSelector(@selector(SSLPinningMode))];
336 [coder encodeBool:self.allowInvalidCertificates forKey:NSStringFromSelector(@selector(allowInvalidCertificates))];
337 [coder encodeBool:self.validatesDomainName forKey:NSStringFromSelector(@selector(validatesDomainName))];
338 [coder encodeObject:self.pinnedCertificates forKey:NSStringFromSelector(@selector(pinnedCertificates))];
339 }
340
341 #pragma mark - NSCopying
342
343 - (instancetype)copyWithZone:(NSZone *)zone {
344 AFSecurityPolicy *securityPolicy = [[[self class] allocWithZone:zone] init];
345 securityPolicy.SSLPinningMode = self.SSLPinningMode;
346 securityPolicy.allowInvalidCertificates = self.allowInvalidCertificates;
347 securityPolicy.validatesDomainName = self.validatesDomainName;
348 securityPolicy.pinnedCertificates = [self.pinnedCertificates copyWithZone:zone];
349
350 return securityPolicy;
351 }
352
353 @end
1 // AFURLRequestSerialization.h
2 // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #import <Foundation/Foundation.h>
23 #import <TargetConditionals.h>
24
25 #if TARGET_OS_IOS || TARGET_OS_TV
26 #import <UIKit/UIKit.h>
27 #elif TARGET_OS_WATCH
28 #import <WatchKit/WatchKit.h>
29 #endif
30
31 NS_ASSUME_NONNULL_BEGIN
32
33 /**
34 Returns a percent-escaped string following RFC 3986 for a query string key or value.
35 RFC 3986 states that the following characters are "reserved" characters.
36 - General Delimiters: ":", "#", "[", "]", "@", "?", "/"
37 - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
38
39 In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
40 query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
41 should be percent-escaped in the query string.
42
43 @param string The string to be percent-escaped.
44
45 @return The percent-escaped string.
46 */
47 FOUNDATION_EXPORT NSString * AFPercentEscapedStringFromString(NSString *string);
48
49 /**
50 A helper method to generate encoded url query parameters for appending to the end of a URL.
51
52 @param parameters A dictionary of key/values to be encoded.
53
54 @return A url encoded query string
55 */
56 FOUNDATION_EXPORT NSString * AFQueryStringFromParameters(NSDictionary *parameters);
57
58 /**
59 The `AFURLRequestSerialization` protocol is adopted by an object that encodes parameters for a specified HTTP requests. Request serializers may encode parameters as query strings, HTTP bodies, setting the appropriate HTTP header fields as necessary.
60
61 For example, a JSON request serializer may set the HTTP body of the request to a JSON representation, and set the `Content-Type` HTTP header field value to `application/json`.
62 */
63 @protocol AFURLRequestSerialization <NSObject, NSSecureCoding, NSCopying>
64
65 /**
66 Returns a request with the specified parameters encoded into a copy of the original request.
67
68 @param request The original request.
69 @param parameters The parameters to be encoded.
70 @param error The error that occurred while attempting to encode the request parameters.
71
72 @return A serialized request.
73 */
74 - (nullable NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
75 withParameters:(nullable id)parameters
76 error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
77
78 @end
79
80 #pragma mark -
81
82 /**
83
84 */
85 typedef NS_ENUM(NSUInteger, AFHTTPRequestQueryStringSerializationStyle) {
86 AFHTTPRequestQueryStringDefaultStyle = 0,
87 };
88
89 @protocol AFMultipartFormData;
90
91 /**
92 `AFHTTPRequestSerializer` conforms to the `AFURLRequestSerialization` & `AFURLResponseSerialization` protocols, offering a concrete base implementation of query string / URL form-encoded parameter serialization and default request headers, as well as response status code and content type validation.
93
94 Any request or response serializer dealing with HTTP is encouraged to subclass `AFHTTPRequestSerializer` in order to ensure consistent default behavior.
95 */
96 @interface AFHTTPRequestSerializer : NSObject <AFURLRequestSerialization>
97
98 /**
99 The string encoding used to serialize parameters. `NSUTF8StringEncoding` by default.
100 */
101 @property (nonatomic, assign) NSStringEncoding stringEncoding;
102
103 /**
104 Whether created requests can use the device’s cellular radio (if present). `YES` by default.
105
106 @see NSMutableURLRequest -setAllowsCellularAccess:
107 */
108 @property (nonatomic, assign) BOOL allowsCellularAccess;
109
110 /**
111 The cache policy of created requests. `NSURLRequestUseProtocolCachePolicy` by default.
112
113 @see NSMutableURLRequest -setCachePolicy:
114 */
115 @property (nonatomic, assign) NSURLRequestCachePolicy cachePolicy;
116
117 /**
118 Whether created requests should use the default cookie handling. `YES` by default.
119
120 @see NSMutableURLRequest -setHTTPShouldHandleCookies:
121 */
122 @property (nonatomic, assign) BOOL HTTPShouldHandleCookies;
123
124 /**
125 Whether created requests can continue transmitting data before receiving a response from an earlier transmission. `NO` by default
126
127 @see NSMutableURLRequest -setHTTPShouldUsePipelining:
128 */
129 @property (nonatomic, assign) BOOL HTTPShouldUsePipelining;
130
131 /**
132 The network service type for created requests. `NSURLNetworkServiceTypeDefault` by default.
133
134 @see NSMutableURLRequest -setNetworkServiceType:
135 */
136 @property (nonatomic, assign) NSURLRequestNetworkServiceType networkServiceType;
137
138 /**
139 The timeout interval, in seconds, for created requests. The default timeout interval is 60 seconds.
140
141 @see NSMutableURLRequest -setTimeoutInterval:
142 */
143 @property (nonatomic, assign) NSTimeInterval timeoutInterval;
144
145 ///---------------------------------------
146 /// @name Configuring HTTP Request Headers
147 ///---------------------------------------
148
149 /**
150 Default HTTP header field values to be applied to serialized requests. By default, these include the following:
151
152 - `Accept-Language` with the contents of `NSLocale +preferredLanguages`
153 - `User-Agent` with the contents of various bundle identifiers and OS designations
154
155 @discussion To add or remove default request headers, use `setValue:forHTTPHeaderField:`.
156 */
157 @property (readonly, nonatomic, strong) NSDictionary <NSString *, NSString *> *HTTPRequestHeaders;
158
159 /**
160 Creates and returns a serializer with default configuration.
161 */
162 + (instancetype)serializer;
163
164 /**
165 Sets the value for the HTTP headers set in request objects made by the HTTP client. If `nil`, removes the existing value for that header.
166
167 @param field The HTTP header to set a default value for
168 @param value The value set as default for the specified header, or `nil`
169 */
170 - (void)setValue:(nullable NSString *)value
171 forHTTPHeaderField:(NSString *)field;
172
173 /**
174 Returns the value for the HTTP headers set in the request serializer.
175
176 @param field The HTTP header to retrieve the default value for
177
178 @return The value set as default for the specified header, or `nil`
179 */
180 - (nullable NSString *)valueForHTTPHeaderField:(NSString *)field;
181
182 /**
183 Sets the "Authorization" HTTP header set in request objects made by the HTTP client to a basic authentication value with Base64-encoded username and password. This overwrites any existing value for this header.
184
185 @param username The HTTP basic auth username
186 @param password The HTTP basic auth password
187 */
188 - (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username
189 password:(NSString *)password;
190
191 /**
192 Clears any existing value for the "Authorization" HTTP header.
193 */
194 - (void)clearAuthorizationHeader;
195
196 ///-------------------------------------------------------
197 /// @name Configuring Query String Parameter Serialization
198 ///-------------------------------------------------------
199
200 /**
201 HTTP methods for which serialized requests will encode parameters as a query string. `GET`, `HEAD`, and `DELETE` by default.
202 */
203 @property (nonatomic, strong) NSSet <NSString *> *HTTPMethodsEncodingParametersInURI;
204
205 /**
206 Set the method of query string serialization according to one of the pre-defined styles.
207
208 @param style The serialization style.
209
210 @see AFHTTPRequestQueryStringSerializationStyle
211 */
212 - (void)setQueryStringSerializationWithStyle:(AFHTTPRequestQueryStringSerializationStyle)style;
213
214 /**
215 Set the a custom method of query string serialization according to the specified block.
216
217 @param block A block that defines a process of encoding parameters into a query string. This block returns the query string and takes three arguments: the request, the parameters to encode, and the error that occurred when attempting to encode parameters for the given request.
218 */
219 - (void)setQueryStringSerializationWithBlock:(nullable NSString * (^)(NSURLRequest *request, id parameters, NSError * __autoreleasing *error))block;
220
221 ///-------------------------------
222 /// @name Creating Request Objects
223 ///-------------------------------
224
225 /**
226 Creates an `NSMutableURLRequest` object with the specified HTTP method and URL string.
227
228 If the HTTP method is `GET`, `HEAD`, or `DELETE`, the parameters will be used to construct a url-encoded query string that is appended to the request's URL. Otherwise, the parameters will be encoded according to the value of the `parameterEncoding` property, and set as the request body.
229
230 @param method The HTTP method for the request, such as `GET`, `POST`, `PUT`, or `DELETE`. This parameter must not be `nil`.
231 @param URLString The URL string used to create the request URL.
232 @param parameters The parameters to be either set as a query string for `GET` requests, or the request HTTP body.
233 @param error The error that occurred while constructing the request.
234
235 @return An `NSMutableURLRequest` object.
236 */
237 - (NSMutableURLRequest *)requestWithMethod:(NSString *)method
238 URLString:(NSString *)URLString
239 parameters:(nullable id)parameters
240 error:(NSError * _Nullable __autoreleasing *)error;
241
242 /**
243 Creates an `NSMutableURLRequest` object with the specified HTTP method and URLString, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2
244
245 Multipart form requests are automatically streamed, reading files directly from disk along with in-memory data in a single HTTP body. The resulting `NSMutableURLRequest` object has an `HTTPBodyStream` property, so refrain from setting `HTTPBodyStream` or `HTTPBody` on this request object, as it will clear out the multipart form body stream.
246
247 @param method The HTTP method for the request. This parameter must not be `GET` or `HEAD`, or `nil`.
248 @param URLString The URL string used to create the request URL.
249 @param parameters The parameters to be encoded and set in the request HTTP body.
250 @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol.
251 @param error The error that occurred while constructing the request.
252
253 @return An `NSMutableURLRequest` object
254 */
255 - (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
256 URLString:(NSString *)URLString
257 parameters:(nullable NSDictionary <NSString *, id> *)parameters
258 constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
259 error:(NSError * _Nullable __autoreleasing *)error;
260
261 /**
262 Creates an `NSMutableURLRequest` by removing the `HTTPBodyStream` from a request, and asynchronously writing its contents into the specified file, invoking the completion handler when finished.
263
264 @param request The multipart form request. The `HTTPBodyStream` property of `request` must not be `nil`.
265 @param fileURL The file URL to write multipart form contents to.
266 @param handler A handler block to execute.
267
268 @discussion There is a bug in `NSURLSessionTask` that causes requests to not send a `Content-Length` header when streaming contents from an HTTP body, which is notably problematic when interacting with the Amazon S3 webservice. As a workaround, this method takes a request constructed with `multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:error:`, or any other request with an `HTTPBodyStream`, writes the contents to the specified file and returns a copy of the original request with the `HTTPBodyStream` property set to `nil`. From here, the file can either be passed to `AFURLSessionManager -uploadTaskWithRequest:fromFile:progress:completionHandler:`, or have its contents read into an `NSData` that's assigned to the `HTTPBody` property of the request.
269
270 @see https://github.com/AFNetworking/AFNetworking/issues/1398
271 */
272 - (NSMutableURLRequest *)requestWithMultipartFormRequest:(NSURLRequest *)request
273 writingStreamContentsToFile:(NSURL *)fileURL
274 completionHandler:(nullable void (^)(NSError * _Nullable error))handler;
275
276 @end
277
278 #pragma mark -
279
280 /**
281 The `AFMultipartFormData` protocol defines the methods supported by the parameter in the block argument of `AFHTTPRequestSerializer -multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:`.
282 */
283 @protocol AFMultipartFormData
284
285 /**
286 Appends the HTTP header `Content-Disposition: file; filename=#{generated filename}; name=#{name}"` and `Content-Type: #{generated mimeType}`, followed by the encoded file data and the multipart form boundary.
287
288 The filename and MIME type for this data in the form will be automatically generated, using the last path component of the `fileURL` and system associated MIME type for the `fileURL` extension, respectively.
289
290 @param fileURL The URL corresponding to the file whose content will be appended to the form. This parameter must not be `nil`.
291 @param name The name to be associated with the specified data. This parameter must not be `nil`.
292 @param error If an error occurs, upon return contains an `NSError` object that describes the problem.
293
294 @return `YES` if the file data was successfully appended, otherwise `NO`.
295 */
296 - (BOOL)appendPartWithFileURL:(NSURL *)fileURL
297 name:(NSString *)name
298 error:(NSError * _Nullable __autoreleasing *)error;
299
300 /**
301 Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary.
302
303 @param fileURL The URL corresponding to the file whose content will be appended to the form. This parameter must not be `nil`.
304 @param name The name to be associated with the specified data. This parameter must not be `nil`.
305 @param fileName The file name to be used in the `Content-Disposition` header. This parameter must not be `nil`.
306 @param mimeType The declared MIME type of the file data. This parameter must not be `nil`.
307 @param error If an error occurs, upon return contains an `NSError` object that describes the problem.
308
309 @return `YES` if the file data was successfully appended otherwise `NO`.
310 */
311 - (BOOL)appendPartWithFileURL:(NSURL *)fileURL
312 name:(NSString *)name
313 fileName:(NSString *)fileName
314 mimeType:(NSString *)mimeType
315 error:(NSError * _Nullable __autoreleasing *)error;
316
317 /**
318 Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the data from the input stream and the multipart form boundary.
319
320 @param inputStream The input stream to be appended to the form data
321 @param name The name to be associated with the specified input stream. This parameter must not be `nil`.
322 @param fileName The filename to be associated with the specified input stream. This parameter must not be `nil`.
323 @param length The length of the specified input stream in bytes.
324 @param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`.
325 */
326 - (void)appendPartWithInputStream:(nullable NSInputStream *)inputStream
327 name:(NSString *)name
328 fileName:(NSString *)fileName
329 length:(int64_t)length
330 mimeType:(NSString *)mimeType;
331
332 /**
333 Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary.
334
335 @param data The data to be encoded and appended to the form data.
336 @param name The name to be associated with the specified data. This parameter must not be `nil`.
337 @param fileName The filename to be associated with the specified data. This parameter must not be `nil`.
338 @param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`.
339 */
340 - (void)appendPartWithFileData:(NSData *)data
341 name:(NSString *)name
342 fileName:(NSString *)fileName
343 mimeType:(NSString *)mimeType;
344
345 /**
346 Appends the HTTP headers `Content-Disposition: form-data; name=#{name}"`, followed by the encoded data and the multipart form boundary.
347
348 @param data The data to be encoded and appended to the form data.
349 @param name The name to be associated with the specified data. This parameter must not be `nil`.
350 */
351
352 - (void)appendPartWithFormData:(NSData *)data
353 name:(NSString *)name;
354
355
356 /**
357 Appends HTTP headers, followed by the encoded data and the multipart form boundary.
358
359 @param headers The HTTP headers to be appended to the form data.
360 @param body The data to be encoded and appended to the form data. This parameter must not be `nil`.
361 */
362 - (void)appendPartWithHeaders:(nullable NSDictionary <NSString *, NSString *> *)headers
363 body:(NSData *)body;
364
365 /**
366 Throttles request bandwidth by limiting the packet size and adding a delay for each chunk read from the upload stream.
367
368 When uploading over a 3G or EDGE connection, requests may fail with "request body stream exhausted". Setting a maximum packet size and delay according to the recommended values (`kAFUploadStream3GSuggestedPacketSize` and `kAFUploadStream3GSuggestedDelay`) lowers the risk of the input stream exceeding its allocated bandwidth. Unfortunately, there is no definite way to distinguish between a 3G, EDGE, or LTE connection over `NSURLConnection`. As such, it is not recommended that you throttle bandwidth based solely on network reachability. Instead, you should consider checking for the "request body stream exhausted" in a failure block, and then retrying the request with throttled bandwidth.
369
370 @param numberOfBytes Maximum packet size, in number of bytes. The default packet size for an input stream is 16kb.
371 @param delay Duration of delay each time a packet is read. By default, no delay is set.
372 */
373 - (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes
374 delay:(NSTimeInterval)delay;
375
376 @end
377
378 #pragma mark -
379
380 /**
381 `AFJSONRequestSerializer` is a subclass of `AFHTTPRequestSerializer` that encodes parameters as JSON using `NSJSONSerialization`, setting the `Content-Type` of the encoded request to `application/json`.
382 */
383 @interface AFJSONRequestSerializer : AFHTTPRequestSerializer
384
385 /**
386 Options for writing the request JSON data from Foundation objects. For possible values, see the `NSJSONSerialization` documentation section "NSJSONWritingOptions". `0` by default.
387 */
388 @property (nonatomic, assign) NSJSONWritingOptions writingOptions;
389
390 /**
391 Creates and returns a JSON serializer with specified reading and writing options.
392
393 @param writingOptions The specified JSON writing options.
394 */
395 + (instancetype)serializerWithWritingOptions:(NSJSONWritingOptions)writingOptions;
396
397 @end
398
399 #pragma mark -
400
401 /**
402 `AFPropertyListRequestSerializer` is a subclass of `AFHTTPRequestSerializer` that encodes parameters as JSON using `NSPropertyListSerializer`, setting the `Content-Type` of the encoded request to `application/x-plist`.
403 */
404 @interface AFPropertyListRequestSerializer : AFHTTPRequestSerializer
405
406 /**
407 The property list format. Possible values are described in "NSPropertyListFormat".
408 */
409 @property (nonatomic, assign) NSPropertyListFormat format;
410
411 /**
412 @warning The `writeOptions` property is currently unused.
413 */
414 @property (nonatomic, assign) NSPropertyListWriteOptions writeOptions;
415
416 /**
417 Creates and returns a property list serializer with a specified format, read options, and write options.
418
419 @param format The property list format.
420 @param writeOptions The property list write options.
421
422 @warning The `writeOptions` property is currently unused.
423 */
424 + (instancetype)serializerWithFormat:(NSPropertyListFormat)format
425 writeOptions:(NSPropertyListWriteOptions)writeOptions;
426
427 @end
428
429 #pragma mark -
430
431 ///----------------
432 /// @name Constants
433 ///----------------
434
435 /**
436 ## Error Domains
437
438 The following error domain is predefined.
439
440 - `NSString * const AFURLRequestSerializationErrorDomain`
441
442 ### Constants
443
444 `AFURLRequestSerializationErrorDomain`
445 AFURLRequestSerializer errors. Error codes for `AFURLRequestSerializationErrorDomain` correspond to codes in `NSURLErrorDomain`.
446 */
447 FOUNDATION_EXPORT NSString * const AFURLRequestSerializationErrorDomain;
448
449 /**
450 ## User info dictionary keys
451
452 These keys may exist in the user info dictionary, in addition to those defined for NSError.
453
454 - `NSString * const AFNetworkingOperationFailingURLRequestErrorKey`
455
456 ### Constants
457
458 `AFNetworkingOperationFailingURLRequestErrorKey`
459 The corresponding value is an `NSURLRequest` containing the request of the operation associated with an error. This key is only present in the `AFURLRequestSerializationErrorDomain`.
460 */
461 FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLRequestErrorKey;
462
463 /**
464 ## Throttling Bandwidth for HTTP Request Input Streams
465
466 @see -throttleBandwidthWithPacketSize:delay:
467
468 ### Constants
469
470 `kAFUploadStream3GSuggestedPacketSize`
471 Maximum packet size, in number of bytes. Equal to 16kb.
472
473 `kAFUploadStream3GSuggestedDelay`
474 Duration of delay each time a packet is read. Equal to 0.2 seconds.
475 */
476 FOUNDATION_EXPORT NSUInteger const kAFUploadStream3GSuggestedPacketSize;
477 FOUNDATION_EXPORT NSTimeInterval const kAFUploadStream3GSuggestedDelay;
478
479 NS_ASSUME_NONNULL_END
1 // AFURLRequestSerialization.m
2 // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #import "AFURLRequestSerialization.h"
23
24 #if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV
25 #import <MobileCoreServices/MobileCoreServices.h>
26 #else
27 #import <CoreServices/CoreServices.h>
28 #endif
29
30 NSString * const AFURLRequestSerializationErrorDomain = @"com.alamofire.error.serialization.request";
31 NSString * const AFNetworkingOperationFailingURLRequestErrorKey = @"com.alamofire.serialization.request.error.response";
32
33 typedef NSString * (^AFQueryStringSerializationBlock)(NSURLRequest *request, id parameters, NSError *__autoreleasing *error);
34
35 /**
36 Returns a percent-escaped string following RFC 3986 for a query string key or value.
37 RFC 3986 states that the following characters are "reserved" characters.
38 - General Delimiters: ":", "#", "[", "]", "@", "?", "/"
39 - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
40
41 In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
42 query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
43 should be percent-escaped in the query string.
44 - parameter string: The string to be percent-escaped.
45 - returns: The percent-escaped string.
46 */
47 NSString * AFPercentEscapedStringFromString(NSString *string) {
48 static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
49 static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";
50
51 NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
52 [allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]];
53
54 // FIXME: https://github.com/AFNetworking/AFNetworking/pull/3028
55 // return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
56
57 static NSUInteger const batchSize = 50;
58
59 NSUInteger index = 0;
60 NSMutableString *escaped = @"".mutableCopy;
61
62 while (index < string.length) {
63 NSUInteger length = MIN(string.length - index, batchSize);
64 NSRange range = NSMakeRange(index, length);
65
66 // To avoid breaking up character sequences such as 👴🏻👮🏽
67 range = [string rangeOfComposedCharacterSequencesForRange:range];
68
69 NSString *substring = [string substringWithRange:range];
70 NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
71 [escaped appendString:encoded];
72
73 index += range.length;
74 }
75
76 return escaped;
77 }
78
79 #pragma mark -
80
81 @interface AFQueryStringPair : NSObject
82 @property (readwrite, nonatomic, strong) id field;
83 @property (readwrite, nonatomic, strong) id value;
84
85 - (instancetype)initWithField:(id)field value:(id)value;
86
87 - (NSString *)URLEncodedStringValue;
88 @end
89
90 @implementation AFQueryStringPair
91
92 - (instancetype)initWithField:(id)field value:(id)value {
93 self = [super init];
94 if (!self) {
95 return nil;
96 }
97
98 self.field = field;
99 self.value = value;
100
101 return self;
102 }
103
104 - (NSString *)URLEncodedStringValue {
105 if (!self.value || [self.value isEqual:[NSNull null]]) {
106 return AFPercentEscapedStringFromString([self.field description]);
107 } else {
108 return [NSString stringWithFormat:@"%@=%@", AFPercentEscapedStringFromString([self.field description]), AFPercentEscapedStringFromString([self.value description])];
109 }
110 }
111
112 @end
113
114 #pragma mark -
115
116 FOUNDATION_EXPORT NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary);
117 FOUNDATION_EXPORT NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value);
118
119 NSString * AFQueryStringFromParameters(NSDictionary *parameters) {
120 NSMutableArray *mutablePairs = [NSMutableArray array];
121 for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
122 [mutablePairs addObject:[pair URLEncodedStringValue]];
123 }
124
125 return [mutablePairs componentsJoinedByString:@"&"];
126 }
127
128 NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary) {
129 return AFQueryStringPairsFromKeyAndValue(nil, dictionary);
130 }
131
132 NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) {
133 NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
134
135 NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)];
136
137 if ([value isKindOfClass:[NSDictionary class]]) {
138 NSDictionary *dictionary = value;
139 // Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries
140 for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
141 id nestedValue = dictionary[nestedKey];
142 if (nestedValue) {
143 [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
144 }
145 }
146 } else if ([value isKindOfClass:[NSArray class]]) {
147 NSArray *array = value;
148 for (id nestedValue in array) {
149 [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];
150 }
151 } else if ([value isKindOfClass:[NSSet class]]) {
152 NSSet *set = value;
153 for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
154 [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)];
155 }
156 } else {
157 [mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]];
158 }
159
160 return mutableQueryStringComponents;
161 }
162
163 #pragma mark -
164
165 @interface AFStreamingMultipartFormData : NSObject <AFMultipartFormData>
166 - (instancetype)initWithURLRequest:(NSMutableURLRequest *)urlRequest
167 stringEncoding:(NSStringEncoding)encoding;
168
169 - (NSMutableURLRequest *)requestByFinalizingMultipartFormData;
170 @end
171
172 #pragma mark -
173
174 static NSArray * AFHTTPRequestSerializerObservedKeyPaths() {
175 static NSArray *_AFHTTPRequestSerializerObservedKeyPaths = nil;
176 static dispatch_once_t onceToken;
177 dispatch_once(&onceToken, ^{
178 _AFHTTPRequestSerializerObservedKeyPaths = @[NSStringFromSelector(@selector(allowsCellularAccess)), NSStringFromSelector(@selector(cachePolicy)), NSStringFromSelector(@selector(HTTPShouldHandleCookies)), NSStringFromSelector(@selector(HTTPShouldUsePipelining)), NSStringFromSelector(@selector(networkServiceType)), NSStringFromSelector(@selector(timeoutInterval))];
179 });
180
181 return _AFHTTPRequestSerializerObservedKeyPaths;
182 }
183
184 static void *AFHTTPRequestSerializerObserverContext = &AFHTTPRequestSerializerObserverContext;
185
186 @interface AFHTTPRequestSerializer ()
187 @property (readwrite, nonatomic, strong) NSMutableSet *mutableObservedChangedKeyPaths;
188 @property (readwrite, nonatomic, strong) NSMutableDictionary *mutableHTTPRequestHeaders;
189 @property (readwrite, nonatomic, strong) dispatch_queue_t requestHeaderModificationQueue;
190 @property (readwrite, nonatomic, assign) AFHTTPRequestQueryStringSerializationStyle queryStringSerializationStyle;
191 @property (readwrite, nonatomic, copy) AFQueryStringSerializationBlock queryStringSerialization;
192 @end
193
194 @implementation AFHTTPRequestSerializer
195
196 + (instancetype)serializer {
197 return [[self alloc] init];
198 }
199
200 - (instancetype)init {
201 self = [super init];
202 if (!self) {
203 return nil;
204 }
205
206 self.stringEncoding = NSUTF8StringEncoding;
207
208 self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary];
209 self.requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT);
210
211 // Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
212 NSMutableArray *acceptLanguagesComponents = [NSMutableArray array];
213 [[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
214 float q = 1.0f - (idx * 0.1f);
215 [acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g", obj, q]];
216 *stop = q <= 0.5f;
217 }];
218 [self setValue:[acceptLanguagesComponents componentsJoinedByString:@", "] forHTTPHeaderField:@"Accept-Language"];
219
220 NSString *userAgent = nil;
221 #if TARGET_OS_IOS
222 // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
223 userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]];
224 #elif TARGET_OS_WATCH
225 // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
226 userAgent = [NSString stringWithFormat:@"%@/%@ (%@; watchOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[WKInterfaceDevice currentDevice] model], [[WKInterfaceDevice currentDevice] systemVersion], [[WKInterfaceDevice currentDevice] screenScale]];
227 #elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
228 userAgent = [NSString stringWithFormat:@"%@/%@ (Mac OS X %@)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]];
229 #endif
230 if (userAgent) {
231 if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) {
232 NSMutableString *mutableUserAgent = [userAgent mutableCopy];
233 if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)) {
234 userAgent = mutableUserAgent;
235 }
236 }
237 [self setValue:userAgent forHTTPHeaderField:@"User-Agent"];
238 }
239
240 // HTTP Method Definitions; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
241 self.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", @"DELETE", nil];
242
243 self.mutableObservedChangedKeyPaths = [NSMutableSet set];
244 for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
245 if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
246 [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];
247 }
248 }
249
250 return self;
251 }
252
253 - (void)dealloc {
254 for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
255 if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
256 [self removeObserver:self forKeyPath:keyPath context:AFHTTPRequestSerializerObserverContext];
257 }
258 }
259 }
260
261 #pragma mark -
262
263 // Workarounds for crashing behavior using Key-Value Observing with XCTest
264 // See https://github.com/AFNetworking/AFNetworking/issues/2523
265
266 - (void)setAllowsCellularAccess:(BOOL)allowsCellularAccess {
267 [self willChangeValueForKey:NSStringFromSelector(@selector(allowsCellularAccess))];
268 _allowsCellularAccess = allowsCellularAccess;
269 [self didChangeValueForKey:NSStringFromSelector(@selector(allowsCellularAccess))];
270 }
271
272 - (void)setCachePolicy:(NSURLRequestCachePolicy)cachePolicy {
273 [self willChangeValueForKey:NSStringFromSelector(@selector(cachePolicy))];
274 _cachePolicy = cachePolicy;
275 [self didChangeValueForKey:NSStringFromSelector(@selector(cachePolicy))];
276 }
277
278 - (void)setHTTPShouldHandleCookies:(BOOL)HTTPShouldHandleCookies {
279 [self willChangeValueForKey:NSStringFromSelector(@selector(HTTPShouldHandleCookies))];
280 _HTTPShouldHandleCookies = HTTPShouldHandleCookies;
281 [self didChangeValueForKey:NSStringFromSelector(@selector(HTTPShouldHandleCookies))];
282 }
283
284 - (void)setHTTPShouldUsePipelining:(BOOL)HTTPShouldUsePipelining {
285 [self willChangeValueForKey:NSStringFromSelector(@selector(HTTPShouldUsePipelining))];
286 _HTTPShouldUsePipelining = HTTPShouldUsePipelining;
287 [self didChangeValueForKey:NSStringFromSelector(@selector(HTTPShouldUsePipelining))];
288 }
289
290 - (void)setNetworkServiceType:(NSURLRequestNetworkServiceType)networkServiceType {
291 [self willChangeValueForKey:NSStringFromSelector(@selector(networkServiceType))];
292 _networkServiceType = networkServiceType;
293 [self didChangeValueForKey:NSStringFromSelector(@selector(networkServiceType))];
294 }
295
296 - (void)setTimeoutInterval:(NSTimeInterval)timeoutInterval {
297 [self willChangeValueForKey:NSStringFromSelector(@selector(timeoutInterval))];
298 _timeoutInterval = timeoutInterval;
299 [self didChangeValueForKey:NSStringFromSelector(@selector(timeoutInterval))];
300 }
301
302 #pragma mark -
303
304 - (NSDictionary *)HTTPRequestHeaders {
305 NSDictionary __block *value;
306 dispatch_sync(self.requestHeaderModificationQueue, ^{
307 value = [NSDictionary dictionaryWithDictionary:self.mutableHTTPRequestHeaders];
308 });
309 return value;
310 }
311
312 - (void)setValue:(NSString *)value
313 forHTTPHeaderField:(NSString *)field
314 {
315 dispatch_barrier_async(self.requestHeaderModificationQueue, ^{
316 [self.mutableHTTPRequestHeaders setValue:value forKey:field];
317 });
318 }
319
320 - (NSString *)valueForHTTPHeaderField:(NSString *)field {
321 NSString __block *value;
322 dispatch_sync(self.requestHeaderModificationQueue, ^{
323 value = [self.mutableHTTPRequestHeaders valueForKey:field];
324 });
325 return value;
326 }
327
328 - (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username
329 password:(NSString *)password
330 {
331 NSData *basicAuthCredentials = [[NSString stringWithFormat:@"%@:%@", username, password] dataUsingEncoding:NSUTF8StringEncoding];
332 NSString *base64AuthCredentials = [basicAuthCredentials base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0];
333 [self setValue:[NSString stringWithFormat:@"Basic %@", base64AuthCredentials] forHTTPHeaderField:@"Authorization"];
334 }
335
336 - (void)clearAuthorizationHeader {
337 dispatch_barrier_async(self.requestHeaderModificationQueue, ^{
338 [self.mutableHTTPRequestHeaders removeObjectForKey:@"Authorization"];
339 });
340 }
341
342 #pragma mark -
343
344 - (void)setQueryStringSerializationWithStyle:(AFHTTPRequestQueryStringSerializationStyle)style {
345 self.queryStringSerializationStyle = style;
346 self.queryStringSerialization = nil;
347 }
348
349 - (void)setQueryStringSerializationWithBlock:(NSString *(^)(NSURLRequest *, id, NSError *__autoreleasing *))block {
350 self.queryStringSerialization = block;
351 }
352
353 #pragma mark -
354
355 - (NSMutableURLRequest *)requestWithMethod:(NSString *)method
356 URLString:(NSString *)URLString
357 parameters:(id)parameters
358 error:(NSError *__autoreleasing *)error
359 {
360 NSParameterAssert(method);
361 NSParameterAssert(URLString);
362
363 NSURL *url = [NSURL URLWithString:URLString];
364
365 NSParameterAssert(url);
366
367 NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
368 mutableRequest.HTTPMethod = method;
369
370 for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
371 if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
372 [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
373 }
374 }
375
376 mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
377
378 return mutableRequest;
379 }
380
381 - (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
382 URLString:(NSString *)URLString
383 parameters:(NSDictionary *)parameters
384 constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
385 error:(NSError *__autoreleasing *)error
386 {
387 NSParameterAssert(method);
388 NSParameterAssert(![method isEqualToString:@"GET"] && ![method isEqualToString:@"HEAD"]);
389
390 NSMutableURLRequest *mutableRequest = [self requestWithMethod:method URLString:URLString parameters:nil error:error];
391
392 __block AFStreamingMultipartFormData *formData = [[AFStreamingMultipartFormData alloc] initWithURLRequest:mutableRequest stringEncoding:NSUTF8StringEncoding];
393
394 if (parameters) {
395 for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
396 NSData *data = nil;
397 if ([pair.value isKindOfClass:[NSData class]]) {
398 data = pair.value;
399 } else if ([pair.value isEqual:[NSNull null]]) {
400 data = [NSData data];
401 } else {
402 data = [[pair.value description] dataUsingEncoding:self.stringEncoding];
403 }
404
405 if (data) {
406 [formData appendPartWithFormData:data name:[pair.field description]];
407 }
408 }
409 }
410
411 if (block) {
412 block(formData);
413 }
414
415 return [formData requestByFinalizingMultipartFormData];
416 }
417
418 - (NSMutableURLRequest *)requestWithMultipartFormRequest:(NSURLRequest *)request
419 writingStreamContentsToFile:(NSURL *)fileURL
420 completionHandler:(void (^)(NSError *error))handler
421 {
422 NSParameterAssert(request.HTTPBodyStream);
423 NSParameterAssert([fileURL isFileURL]);
424
425 NSInputStream *inputStream = request.HTTPBodyStream;
426 NSOutputStream *outputStream = [[NSOutputStream alloc] initWithURL:fileURL append:NO];
427 __block NSError *error = nil;
428
429 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
430 [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
431 [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
432
433 [inputStream open];
434 [outputStream open];
435
436 while ([inputStream hasBytesAvailable] && [outputStream hasSpaceAvailable]) {
437 uint8_t buffer[1024];
438
439 NSInteger bytesRead = [inputStream read:buffer maxLength:1024];
440 if (inputStream.streamError || bytesRead < 0) {
441 error = inputStream.streamError;
442 break;
443 }
444
445 NSInteger bytesWritten = [outputStream write:buffer maxLength:(NSUInteger)bytesRead];
446 if (outputStream.streamError || bytesWritten < 0) {
447 error = outputStream.streamError;
448 break;
449 }
450
451 if (bytesRead == 0 && bytesWritten == 0) {
452 break;
453 }
454 }
455
456 [outputStream close];
457 [inputStream close];
458
459 if (handler) {
460 dispatch_async(dispatch_get_main_queue(), ^{
461 handler(error);
462 });
463 }
464 });
465
466 NSMutableURLRequest *mutableRequest = [request mutableCopy];
467 mutableRequest.HTTPBodyStream = nil;
468
469 return mutableRequest;
470 }
471
472 #pragma mark - AFURLRequestSerialization
473
474 - (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
475 withParameters:(id)parameters
476 error:(NSError *__autoreleasing *)error
477 {
478 NSParameterAssert(request);
479
480 NSMutableURLRequest *mutableRequest = [request mutableCopy];
481
482 [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
483 if (![request valueForHTTPHeaderField:field]) {
484 [mutableRequest setValue:value forHTTPHeaderField:field];
485 }
486 }];
487
488 NSString *query = nil;
489 if (parameters) {
490 if (self.queryStringSerialization) {
491 NSError *serializationError;
492 query = self.queryStringSerialization(request, parameters, &serializationError);
493
494 if (serializationError) {
495 if (error) {
496 *error = serializationError;
497 }
498
499 return nil;
500 }
501 } else {
502 switch (self.queryStringSerializationStyle) {
503 case AFHTTPRequestQueryStringDefaultStyle:
504 query = AFQueryStringFromParameters(parameters);
505 break;
506 }
507 }
508 }
509
510 if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
511 if (query && query.length > 0) {
512 mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];
513 }
514 } else {
515 // #2864: an empty string is a valid x-www-form-urlencoded payload
516 if (!query) {
517 query = @"";
518 }
519 if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
520 [mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
521 }
522 [mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
523 }
524
525 return mutableRequest;
526 }
527
528 #pragma mark - NSKeyValueObserving
529
530 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
531 if ([AFHTTPRequestSerializerObservedKeyPaths() containsObject:key]) {
532 return NO;
533 }
534
535 return [super automaticallyNotifiesObserversForKey:key];
536 }
537
538 - (void)observeValueForKeyPath:(NSString *)keyPath
539 ofObject:(__unused id)object
540 change:(NSDictionary *)change
541 context:(void *)context
542 {
543 if (context == AFHTTPRequestSerializerObserverContext) {
544 if ([change[NSKeyValueChangeNewKey] isEqual:[NSNull null]]) {
545 [self.mutableObservedChangedKeyPaths removeObject:keyPath];
546 } else {
547 [self.mutableObservedChangedKeyPaths addObject:keyPath];
548 }
549 }
550 }
551
552 #pragma mark - NSSecureCoding
553
554 + (BOOL)supportsSecureCoding {
555 return YES;
556 }
557
558 - (instancetype)initWithCoder:(NSCoder *)decoder {
559 self = [self init];
560 if (!self) {
561 return nil;
562 }
563
564 self.mutableHTTPRequestHeaders = [[decoder decodeObjectOfClass:[NSDictionary class] forKey:NSStringFromSelector(@selector(mutableHTTPRequestHeaders))] mutableCopy];
565 self.queryStringSerializationStyle = (AFHTTPRequestQueryStringSerializationStyle)[[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(queryStringSerializationStyle))] unsignedIntegerValue];
566
567 return self;
568 }
569
570 - (void)encodeWithCoder:(NSCoder *)coder {
571 dispatch_sync(self.requestHeaderModificationQueue, ^{
572 [coder encodeObject:self.mutableHTTPRequestHeaders forKey:NSStringFromSelector(@selector(mutableHTTPRequestHeaders))];
573 });
574 [coder encodeInteger:self.queryStringSerializationStyle forKey:NSStringFromSelector(@selector(queryStringSerializationStyle))];
575 }
576
577 #pragma mark - NSCopying
578
579 - (instancetype)copyWithZone:(NSZone *)zone {
580 AFHTTPRequestSerializer *serializer = [[[self class] allocWithZone:zone] init];
581 dispatch_sync(self.requestHeaderModificationQueue, ^{
582 serializer.mutableHTTPRequestHeaders = [self.mutableHTTPRequestHeaders mutableCopyWithZone:zone];
583 });
584 serializer.queryStringSerializationStyle = self.queryStringSerializationStyle;
585 serializer.queryStringSerialization = self.queryStringSerialization;
586
587 return serializer;
588 }
589
590 @end
591
592 #pragma mark -
593
594 static NSString * AFCreateMultipartFormBoundary() {
595 return [NSString stringWithFormat:@"Boundary+%08X%08X", arc4random(), arc4random()];
596 }
597
598 static NSString * const kAFMultipartFormCRLF = @"\r\n";
599
600 static inline NSString * AFMultipartFormInitialBoundary(NSString *boundary) {
601 return [NSString stringWithFormat:@"--%@%@", boundary, kAFMultipartFormCRLF];
602 }
603
604 static inline NSString * AFMultipartFormEncapsulationBoundary(NSString *boundary) {
605 return [NSString stringWithFormat:@"%@--%@%@", kAFMultipartFormCRLF, boundary, kAFMultipartFormCRLF];
606 }
607
608 static inline NSString * AFMultipartFormFinalBoundary(NSString *boundary) {
609 return [NSString stringWithFormat:@"%@--%@--%@", kAFMultipartFormCRLF, boundary, kAFMultipartFormCRLF];
610 }
611
612 static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
613 NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);
614 NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType);
615 if (!contentType) {
616 return @"application/octet-stream";
617 } else {
618 return contentType;
619 }
620 }
621
622 NSUInteger const kAFUploadStream3GSuggestedPacketSize = 1024 * 16;
623 NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
624
625 @interface AFHTTPBodyPart : NSObject
626 @property (nonatomic, assign) NSStringEncoding stringEncoding;
627 @property (nonatomic, strong) NSDictionary *headers;
628 @property (nonatomic, copy) NSString *boundary;
629 @property (nonatomic, strong) id body;
630 @property (nonatomic, assign) unsigned long long bodyContentLength;
631 @property (nonatomic, strong) NSInputStream *inputStream;
632
633 @property (nonatomic, assign) BOOL hasInitialBoundary;
634 @property (nonatomic, assign) BOOL hasFinalBoundary;
635
636 @property (readonly, nonatomic, assign, getter = hasBytesAvailable) BOOL bytesAvailable;
637 @property (readonly, nonatomic, assign) unsigned long long contentLength;
638
639 - (NSInteger)read:(uint8_t *)buffer
640 maxLength:(NSUInteger)length;
641 @end
642
643 @interface AFMultipartBodyStream : NSInputStream <NSStreamDelegate>
644 @property (nonatomic, assign) NSUInteger numberOfBytesInPacket;
645 @property (nonatomic, assign) NSTimeInterval delay;
646 @property (nonatomic, strong) NSInputStream *inputStream;
647 @property (readonly, nonatomic, assign) unsigned long long contentLength;
648 @property (readonly, nonatomic, assign, getter = isEmpty) BOOL empty;
649
650 - (instancetype)initWithStringEncoding:(NSStringEncoding)encoding;
651 - (void)setInitialAndFinalBoundaries;
652 - (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart;
653 @end
654
655 #pragma mark -
656
657 @interface AFStreamingMultipartFormData ()
658 @property (readwrite, nonatomic, copy) NSMutableURLRequest *request;
659 @property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding;
660 @property (readwrite, nonatomic, copy) NSString *boundary;
661 @property (readwrite, nonatomic, strong) AFMultipartBodyStream *bodyStream;
662 @end
663
664 @implementation AFStreamingMultipartFormData
665
666 - (instancetype)initWithURLRequest:(NSMutableURLRequest *)urlRequest
667 stringEncoding:(NSStringEncoding)encoding
668 {
669 self = [super init];
670 if (!self) {
671 return nil;
672 }
673
674 self.request = urlRequest;
675 self.stringEncoding = encoding;
676 self.boundary = AFCreateMultipartFormBoundary();
677 self.bodyStream = [[AFMultipartBodyStream alloc] initWithStringEncoding:encoding];
678
679 return self;
680 }
681
682 - (BOOL)appendPartWithFileURL:(NSURL *)fileURL
683 name:(NSString *)name
684 error:(NSError * __autoreleasing *)error
685 {
686 NSParameterAssert(fileURL);
687 NSParameterAssert(name);
688
689 NSString *fileName = [fileURL lastPathComponent];
690 NSString *mimeType = AFContentTypeForPathExtension([fileURL pathExtension]);
691
692 return [self appendPartWithFileURL:fileURL name:name fileName:fileName mimeType:mimeType error:error];
693 }
694
695 - (BOOL)appendPartWithFileURL:(NSURL *)fileURL
696 name:(NSString *)name
697 fileName:(NSString *)fileName
698 mimeType:(NSString *)mimeType
699 error:(NSError * __autoreleasing *)error
700 {
701 NSParameterAssert(fileURL);
702 NSParameterAssert(name);
703 NSParameterAssert(fileName);
704 NSParameterAssert(mimeType);
705
706 if (![fileURL isFileURL]) {
707 NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: NSLocalizedStringFromTable(@"Expected URL to be a file URL", @"AFNetworking", nil)};
708 if (error) {
709 *error = [[NSError alloc] initWithDomain:AFURLRequestSerializationErrorDomain code:NSURLErrorBadURL userInfo:userInfo];
710 }
711
712 return NO;
713 } else if ([fileURL checkResourceIsReachableAndReturnError:error] == NO) {
714 NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: NSLocalizedStringFromTable(@"File URL not reachable.", @"AFNetworking", nil)};
715 if (error) {
716 *error = [[NSError alloc] initWithDomain:AFURLRequestSerializationErrorDomain code:NSURLErrorBadURL userInfo:userInfo];
717 }
718
719 return NO;
720 }
721
722 NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[fileURL path] error:error];
723 if (!fileAttributes) {
724 return NO;
725 }
726
727 NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
728 [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"];
729 [mutableHeaders setValue:mimeType forKey:@"Content-Type"];
730
731 AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init];
732 bodyPart.stringEncoding = self.stringEncoding;
733 bodyPart.headers = mutableHeaders;
734 bodyPart.boundary = self.boundary;
735 bodyPart.body = fileURL;
736 bodyPart.bodyContentLength = [fileAttributes[NSFileSize] unsignedLongLongValue];
737 [self.bodyStream appendHTTPBodyPart:bodyPart];
738
739 return YES;
740 }
741
742 - (void)appendPartWithInputStream:(NSInputStream *)inputStream
743 name:(NSString *)name
744 fileName:(NSString *)fileName
745 length:(int64_t)length
746 mimeType:(NSString *)mimeType
747 {
748 NSParameterAssert(name);
749 NSParameterAssert(fileName);
750 NSParameterAssert(mimeType);
751
752 NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
753 [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"];
754 [mutableHeaders setValue:mimeType forKey:@"Content-Type"];
755
756 AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init];
757 bodyPart.stringEncoding = self.stringEncoding;
758 bodyPart.headers = mutableHeaders;
759 bodyPart.boundary = self.boundary;
760 bodyPart.body = inputStream;
761
762 bodyPart.bodyContentLength = (unsigned long long)length;
763
764 [self.bodyStream appendHTTPBodyPart:bodyPart];
765 }
766
767 - (void)appendPartWithFileData:(NSData *)data
768 name:(NSString *)name
769 fileName:(NSString *)fileName
770 mimeType:(NSString *)mimeType
771 {
772 NSParameterAssert(name);
773 NSParameterAssert(fileName);
774 NSParameterAssert(mimeType);
775
776 NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
777 [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"];
778 [mutableHeaders setValue:mimeType forKey:@"Content-Type"];
779
780 [self appendPartWithHeaders:mutableHeaders body:data];
781 }
782
783 - (void)appendPartWithFormData:(NSData *)data
784 name:(NSString *)name
785 {
786 NSParameterAssert(name);
787
788 NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
789 [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"", name] forKey:@"Content-Disposition"];
790
791 [self appendPartWithHeaders:mutableHeaders body:data];
792 }
793
794 - (void)appendPartWithHeaders:(NSDictionary *)headers
795 body:(NSData *)body
796 {
797 NSParameterAssert(body);
798
799 AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init];
800 bodyPart.stringEncoding = self.stringEncoding;
801 bodyPart.headers = headers;
802 bodyPart.boundary = self.boundary;
803 bodyPart.bodyContentLength = [body length];
804 bodyPart.body = body;
805
806 [self.bodyStream appendHTTPBodyPart:bodyPart];
807 }
808
809 - (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes
810 delay:(NSTimeInterval)delay
811 {
812 self.bodyStream.numberOfBytesInPacket = numberOfBytes;
813 self.bodyStream.delay = delay;
814 }
815
816 - (NSMutableURLRequest *)requestByFinalizingMultipartFormData {
817 if ([self.bodyStream isEmpty]) {
818 return self.request;
819 }
820
821 // Reset the initial and final boundaries to ensure correct Content-Length
822 [self.bodyStream setInitialAndFinalBoundaries];
823 [self.request setHTTPBodyStream:self.bodyStream];
824
825 [self.request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", self.boundary] forHTTPHeaderField:@"Content-Type"];
826 [self.request setValue:[NSString stringWithFormat:@"%llu", [self.bodyStream contentLength]] forHTTPHeaderField:@"Content-Length"];
827
828 return self.request;
829 }
830
831 @end
832
833 #pragma mark -
834
835 @interface NSStream ()
836 @property (readwrite) NSStreamStatus streamStatus;
837 @property (readwrite, copy) NSError *streamError;
838 @end
839
840 @interface AFMultipartBodyStream () <NSCopying>
841 @property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding;
842 @property (readwrite, nonatomic, strong) NSMutableArray *HTTPBodyParts;
843 @property (readwrite, nonatomic, strong) NSEnumerator *HTTPBodyPartEnumerator;
844 @property (readwrite, nonatomic, strong) AFHTTPBodyPart *currentHTTPBodyPart;
845 @property (readwrite, nonatomic, strong) NSOutputStream *outputStream;
846 @property (readwrite, nonatomic, strong) NSMutableData *buffer;
847 @end
848
849 @implementation AFMultipartBodyStream
850 #if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1100)
851 @synthesize delegate;
852 #endif
853 @synthesize streamStatus;
854 @synthesize streamError;
855
856 - (instancetype)initWithStringEncoding:(NSStringEncoding)encoding {
857 self = [super init];
858 if (!self) {
859 return nil;
860 }
861
862 self.stringEncoding = encoding;
863 self.HTTPBodyParts = [NSMutableArray array];
864 self.numberOfBytesInPacket = NSIntegerMax;
865
866 return self;
867 }
868
869 - (void)setInitialAndFinalBoundaries {
870 if ([self.HTTPBodyParts count] > 0) {
871 for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
872 bodyPart.hasInitialBoundary = NO;
873 bodyPart.hasFinalBoundary = NO;
874 }
875
876 [[self.HTTPBodyParts firstObject] setHasInitialBoundary:YES];
877 [[self.HTTPBodyParts lastObject] setHasFinalBoundary:YES];
878 }
879 }
880
881 - (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart {
882 [self.HTTPBodyParts addObject:bodyPart];
883 }
884
885 - (BOOL)isEmpty {
886 return [self.HTTPBodyParts count] == 0;
887 }
888
889 #pragma mark - NSInputStream
890
891 - (NSInteger)read:(uint8_t *)buffer
892 maxLength:(NSUInteger)length
893 {
894 if ([self streamStatus] == NSStreamStatusClosed) {
895 return 0;
896 }
897
898 NSInteger totalNumberOfBytesRead = 0;
899
900 while ((NSUInteger)totalNumberOfBytesRead < MIN(length, self.numberOfBytesInPacket)) {
901 if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) {
902 if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) {
903 break;
904 }
905 } else {
906 NSUInteger maxLength = MIN(length, self.numberOfBytesInPacket) - (NSUInteger)totalNumberOfBytesRead;
907 NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read:&buffer[totalNumberOfBytesRead] maxLength:maxLength];
908 if (numberOfBytesRead == -1) {
909 self.streamError = self.currentHTTPBodyPart.inputStream.streamError;
910 break;
911 } else {
912 totalNumberOfBytesRead += numberOfBytesRead;
913
914 if (self.delay > 0.0f) {
915 [NSThread sleepForTimeInterval:self.delay];
916 }
917 }
918 }
919 }
920
921 return totalNumberOfBytesRead;
922 }
923
924 - (BOOL)getBuffer:(__unused uint8_t **)buffer
925 length:(__unused NSUInteger *)len
926 {
927 return NO;
928 }
929
930 - (BOOL)hasBytesAvailable {
931 return [self streamStatus] == NSStreamStatusOpen;
932 }
933
934 #pragma mark - NSStream
935
936 - (void)open {
937 if (self.streamStatus == NSStreamStatusOpen) {
938 return;
939 }
940
941 self.streamStatus = NSStreamStatusOpen;
942
943 [self setInitialAndFinalBoundaries];
944 self.HTTPBodyPartEnumerator = [self.HTTPBodyParts objectEnumerator];
945 }
946
947 - (void)close {
948 self.streamStatus = NSStreamStatusClosed;
949 }
950
951 - (id)propertyForKey:(__unused NSString *)key {
952 return nil;
953 }
954
955 - (BOOL)setProperty:(__unused id)property
956 forKey:(__unused NSString *)key
957 {
958 return NO;
959 }
960
961 - (void)scheduleInRunLoop:(__unused NSRunLoop *)aRunLoop
962 forMode:(__unused NSString *)mode
963 {}
964
965 - (void)removeFromRunLoop:(__unused NSRunLoop *)aRunLoop
966 forMode:(__unused NSString *)mode
967 {}
968
969 - (unsigned long long)contentLength {
970 unsigned long long length = 0;
971 for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
972 length += [bodyPart contentLength];
973 }
974
975 return length;
976 }
977
978 #pragma mark - Undocumented CFReadStream Bridged Methods
979
980 - (void)_scheduleInCFRunLoop:(__unused CFRunLoopRef)aRunLoop
981 forMode:(__unused CFStringRef)aMode
982 {}
983
984 - (void)_unscheduleFromCFRunLoop:(__unused CFRunLoopRef)aRunLoop
985 forMode:(__unused CFStringRef)aMode
986 {}
987
988 - (BOOL)_setCFClientFlags:(__unused CFOptionFlags)inFlags
989 callback:(__unused CFReadStreamClientCallBack)inCallback
990 context:(__unused CFStreamClientContext *)inContext {
991 return NO;
992 }
993
994 #pragma mark - NSCopying
995
996 - (instancetype)copyWithZone:(NSZone *)zone {
997 AFMultipartBodyStream *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding];
998
999 for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
1000 [bodyStreamCopy appendHTTPBodyPart:[bodyPart copy]];
1001 }
1002
1003 [bodyStreamCopy setInitialAndFinalBoundaries];
1004
1005 return bodyStreamCopy;
1006 }
1007
1008 @end
1009
1010 #pragma mark -
1011
1012 typedef enum {
1013 AFEncapsulationBoundaryPhase = 1,
1014 AFHeaderPhase = 2,
1015 AFBodyPhase = 3,
1016 AFFinalBoundaryPhase = 4,
1017 } AFHTTPBodyPartReadPhase;
1018
1019 @interface AFHTTPBodyPart () <NSCopying> {
1020 AFHTTPBodyPartReadPhase _phase;
1021 NSInputStream *_inputStream;
1022 unsigned long long _phaseReadOffset;
1023 }
1024
1025 - (BOOL)transitionToNextPhase;
1026 - (NSInteger)readData:(NSData *)data
1027 intoBuffer:(uint8_t *)buffer
1028 maxLength:(NSUInteger)length;
1029 @end
1030
1031 @implementation AFHTTPBodyPart
1032
1033 - (instancetype)init {
1034 self = [super init];
1035 if (!self) {
1036 return nil;
1037 }
1038
1039 [self transitionToNextPhase];
1040
1041 return self;
1042 }
1043
1044 - (void)dealloc {
1045 if (_inputStream) {
1046 [_inputStream close];
1047 _inputStream = nil;
1048 }
1049 }
1050
1051 - (NSInputStream *)inputStream {
1052 if (!_inputStream) {
1053 if ([self.body isKindOfClass:[NSData class]]) {
1054 _inputStream = [NSInputStream inputStreamWithData:self.body];
1055 } else if ([self.body isKindOfClass:[NSURL class]]) {
1056 _inputStream = [NSInputStream inputStreamWithURL:self.body];
1057 } else if ([self.body isKindOfClass:[NSInputStream class]]) {
1058 _inputStream = self.body;
1059 } else {
1060 _inputStream = [NSInputStream inputStreamWithData:[NSData data]];
1061 }
1062 }
1063
1064 return _inputStream;
1065 }
1066
1067 - (NSString *)stringForHeaders {
1068 NSMutableString *headerString = [NSMutableString string];
1069 for (NSString *field in [self.headers allKeys]) {
1070 [headerString appendString:[NSString stringWithFormat:@"%@: %@%@", field, [self.headers valueForKey:field], kAFMultipartFormCRLF]];
1071 }
1072 [headerString appendString:kAFMultipartFormCRLF];
1073
1074 return [NSString stringWithString:headerString];
1075 }
1076
1077 - (unsigned long long)contentLength {
1078 unsigned long long length = 0;
1079
1080 NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary(self.boundary) : AFMultipartFormEncapsulationBoundary(self.boundary)) dataUsingEncoding:self.stringEncoding];
1081 length += [encapsulationBoundaryData length];
1082
1083 NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding];
1084 length += [headersData length];
1085
1086 length += _bodyContentLength;
1087
1088 NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary(self.boundary) dataUsingEncoding:self.stringEncoding] : [NSData data]);
1089 length += [closingBoundaryData length];
1090
1091 return length;
1092 }
1093
1094 - (BOOL)hasBytesAvailable {
1095 // Allows `read:maxLength:` to be called again if `AFMultipartFormFinalBoundary` doesn't fit into the available buffer
1096 if (_phase == AFFinalBoundaryPhase) {
1097 return YES;
1098 }
1099
1100 switch (self.inputStream.streamStatus) {
1101 case NSStreamStatusNotOpen:
1102 case NSStreamStatusOpening:
1103 case NSStreamStatusOpen:
1104 case NSStreamStatusReading:
1105 case NSStreamStatusWriting:
1106 return YES;
1107 case NSStreamStatusAtEnd:
1108 case NSStreamStatusClosed:
1109 case NSStreamStatusError:
1110 default:
1111 return NO;
1112 }
1113 }
1114
1115 - (NSInteger)read:(uint8_t *)buffer
1116 maxLength:(NSUInteger)length
1117 {
1118 NSInteger totalNumberOfBytesRead = 0;
1119
1120 if (_phase == AFEncapsulationBoundaryPhase) {
1121 NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary(self.boundary) : AFMultipartFormEncapsulationBoundary(self.boundary)) dataUsingEncoding:self.stringEncoding];
1122 totalNumberOfBytesRead += [self readData:encapsulationBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)];
1123 }
1124
1125 if (_phase == AFHeaderPhase) {
1126 NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding];
1127 totalNumberOfBytesRead += [self readData:headersData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)];
1128 }
1129
1130 if (_phase == AFBodyPhase) {
1131 NSInteger numberOfBytesRead = 0;
1132
1133 numberOfBytesRead = [self.inputStream read:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)];
1134 if (numberOfBytesRead == -1) {
1135 return -1;
1136 } else {
1137 totalNumberOfBytesRead += numberOfBytesRead;
1138
1139 if ([self.inputStream streamStatus] >= NSStreamStatusAtEnd) {
1140 [self transitionToNextPhase];
1141 }
1142 }
1143 }
1144
1145 if (_phase == AFFinalBoundaryPhase) {
1146 NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary(self.boundary) dataUsingEncoding:self.stringEncoding] : [NSData data]);
1147 totalNumberOfBytesRead += [self readData:closingBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)];
1148 }
1149
1150 return totalNumberOfBytesRead;
1151 }
1152
1153 - (NSInteger)readData:(NSData *)data
1154 intoBuffer:(uint8_t *)buffer
1155 maxLength:(NSUInteger)length
1156 {
1157 NSRange range = NSMakeRange((NSUInteger)_phaseReadOffset, MIN([data length] - ((NSUInteger)_phaseReadOffset), length));
1158 [data getBytes:buffer range:range];
1159
1160 _phaseReadOffset += range.length;
1161
1162 if (((NSUInteger)_phaseReadOffset) >= [data length]) {
1163 [self transitionToNextPhase];
1164 }
1165
1166 return (NSInteger)range.length;
1167 }
1168
1169 - (BOOL)transitionToNextPhase {
1170 if (![[NSThread currentThread] isMainThread]) {
1171 dispatch_sync(dispatch_get_main_queue(), ^{
1172 [self transitionToNextPhase];
1173 });
1174 return YES;
1175 }
1176
1177 switch (_phase) {
1178 case AFEncapsulationBoundaryPhase:
1179 _phase = AFHeaderPhase;
1180 break;
1181 case AFHeaderPhase:
1182 [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
1183 [self.inputStream open];
1184 _phase = AFBodyPhase;
1185 break;
1186 case AFBodyPhase:
1187 [self.inputStream close];
1188 _phase = AFFinalBoundaryPhase;
1189 break;
1190 case AFFinalBoundaryPhase:
1191 default:
1192 _phase = AFEncapsulationBoundaryPhase;
1193 break;
1194 }
1195 _phaseReadOffset = 0;
1196
1197 return YES;
1198 }
1199
1200 #pragma mark - NSCopying
1201
1202 - (instancetype)copyWithZone:(NSZone *)zone {
1203 AFHTTPBodyPart *bodyPart = [[[self class] allocWithZone:zone] init];
1204
1205 bodyPart.stringEncoding = self.stringEncoding;
1206 bodyPart.headers = self.headers;
1207 bodyPart.bodyContentLength = self.bodyContentLength;
1208 bodyPart.body = self.body;
1209 bodyPart.boundary = self.boundary;
1210
1211 return bodyPart;
1212 }
1213
1214 @end
1215
1216 #pragma mark -
1217
1218 @implementation AFJSONRequestSerializer
1219
1220 + (instancetype)serializer {
1221 return [self serializerWithWritingOptions:(NSJSONWritingOptions)0];
1222 }
1223
1224 + (instancetype)serializerWithWritingOptions:(NSJSONWritingOptions)writingOptions
1225 {
1226 AFJSONRequestSerializer *serializer = [[self alloc] init];
1227 serializer.writingOptions = writingOptions;
1228
1229 return serializer;
1230 }
1231
1232 #pragma mark - AFURLRequestSerialization
1233
1234 - (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
1235 withParameters:(id)parameters
1236 error:(NSError *__autoreleasing *)error
1237 {
1238 NSParameterAssert(request);
1239
1240 if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
1241 return [super requestBySerializingRequest:request withParameters:parameters error:error];
1242 }
1243
1244 NSMutableURLRequest *mutableRequest = [request mutableCopy];
1245
1246 [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
1247 if (![request valueForHTTPHeaderField:field]) {
1248 [mutableRequest setValue:value forHTTPHeaderField:field];
1249 }
1250 }];
1251
1252 if (parameters) {
1253 if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
1254 [mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
1255 }
1256
1257 [mutableRequest setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error]];
1258 }
1259
1260 return mutableRequest;
1261 }
1262
1263 #pragma mark - NSSecureCoding
1264
1265 - (instancetype)initWithCoder:(NSCoder *)decoder {
1266 self = [super initWithCoder:decoder];
1267 if (!self) {
1268 return nil;
1269 }
1270
1271 self.writingOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(writingOptions))] unsignedIntegerValue];
1272
1273 return self;
1274 }
1275
1276 - (void)encodeWithCoder:(NSCoder *)coder {
1277 [super encodeWithCoder:coder];
1278
1279 [coder encodeInteger:self.writingOptions forKey:NSStringFromSelector(@selector(writingOptions))];
1280 }
1281
1282 #pragma mark - NSCopying
1283
1284 - (instancetype)copyWithZone:(NSZone *)zone {
1285 AFJSONRequestSerializer *serializer = [super copyWithZone:zone];
1286 serializer.writingOptions = self.writingOptions;
1287
1288 return serializer;
1289 }
1290
1291 @end
1292
1293 #pragma mark -
1294
1295 @implementation AFPropertyListRequestSerializer
1296
1297 + (instancetype)serializer {
1298 return [self serializerWithFormat:NSPropertyListXMLFormat_v1_0 writeOptions:0];
1299 }
1300
1301 + (instancetype)serializerWithFormat:(NSPropertyListFormat)format
1302 writeOptions:(NSPropertyListWriteOptions)writeOptions
1303 {
1304 AFPropertyListRequestSerializer *serializer = [[self alloc] init];
1305 serializer.format = format;
1306 serializer.writeOptions = writeOptions;
1307
1308 return serializer;
1309 }
1310
1311 #pragma mark - AFURLRequestSerializer
1312
1313 - (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
1314 withParameters:(id)parameters
1315 error:(NSError *__autoreleasing *)error
1316 {
1317 NSParameterAssert(request);
1318
1319 if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
1320 return [super requestBySerializingRequest:request withParameters:parameters error:error];
1321 }
1322
1323 NSMutableURLRequest *mutableRequest = [request mutableCopy];
1324
1325 [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
1326 if (![request valueForHTTPHeaderField:field]) {
1327 [mutableRequest setValue:value forHTTPHeaderField:field];
1328 }
1329 }];
1330
1331 if (parameters) {
1332 if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
1333 [mutableRequest setValue:@"application/x-plist" forHTTPHeaderField:@"Content-Type"];
1334 }
1335
1336 [mutableRequest setHTTPBody:[NSPropertyListSerialization dataWithPropertyList:parameters format:self.format options:self.writeOptions error:error]];
1337 }
1338
1339 return mutableRequest;
1340 }
1341
1342 #pragma mark - NSSecureCoding
1343
1344 - (instancetype)initWithCoder:(NSCoder *)decoder {
1345 self = [super initWithCoder:decoder];
1346 if (!self) {
1347 return nil;
1348 }
1349
1350 self.format = (NSPropertyListFormat)[[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(format))] unsignedIntegerValue];
1351 self.writeOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(writeOptions))] unsignedIntegerValue];
1352
1353 return self;
1354 }
1355
1356 - (void)encodeWithCoder:(NSCoder *)coder {
1357 [super encodeWithCoder:coder];
1358
1359 [coder encodeInteger:self.format forKey:NSStringFromSelector(@selector(format))];
1360 [coder encodeObject:@(self.writeOptions) forKey:NSStringFromSelector(@selector(writeOptions))];
1361 }
1362
1363 #pragma mark - NSCopying
1364
1365 - (instancetype)copyWithZone:(NSZone *)zone {
1366 AFPropertyListRequestSerializer *serializer = [super copyWithZone:zone];
1367 serializer.format = self.format;
1368 serializer.writeOptions = self.writeOptions;
1369
1370 return serializer;
1371 }
1372
1373 @end
1 // AFURLResponseSerialization.h
2 // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #import <Foundation/Foundation.h>
23 #import <CoreGraphics/CoreGraphics.h>
24
25 NS_ASSUME_NONNULL_BEGIN
26
27 /**
28 The `AFURLResponseSerialization` protocol is adopted by an object that decodes data into a more useful object representation, according to details in the server response. Response serializers may additionally perform validation on the incoming response and data.
29
30 For example, a JSON response serializer may check for an acceptable status code (`2XX` range) and content type (`application/json`), decoding a valid JSON response into an object.
31 */
32 @protocol AFURLResponseSerialization <NSObject, NSSecureCoding, NSCopying>
33
34 /**
35 The response object decoded from the data associated with a specified response.
36
37 @param response The response to be processed.
38 @param data The response data to be decoded.
39 @param error The error that occurred while attempting to decode the response data.
40
41 @return The object decoded from the specified response data.
42 */
43 - (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
44 data:(nullable NSData *)data
45 error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
46
47 @end
48
49 #pragma mark -
50
51 /**
52 `AFHTTPResponseSerializer` conforms to the `AFURLRequestSerialization` & `AFURLResponseSerialization` protocols, offering a concrete base implementation of query string / URL form-encoded parameter serialization and default request headers, as well as response status code and content type validation.
53
54 Any request or response serializer dealing with HTTP is encouraged to subclass `AFHTTPResponseSerializer` in order to ensure consistent default behavior.
55 */
56 @interface AFHTTPResponseSerializer : NSObject <AFURLResponseSerialization>
57
58 - (instancetype)init;
59
60 /**
61 The string encoding used to serialize data received from the server, when no string encoding is specified by the response. `NSUTF8StringEncoding` by default.
62 */
63 @property (nonatomic, assign) NSStringEncoding stringEncoding;
64
65 /**
66 Creates and returns a serializer with default configuration.
67 */
68 + (instancetype)serializer;
69
70 ///-----------------------------------------
71 /// @name Configuring Response Serialization
72 ///-----------------------------------------
73
74 /**
75 The acceptable HTTP status codes for responses. When non-`nil`, responses with status codes not contained by the set will result in an error during validation.
76
77 See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
78 */
79 @property (nonatomic, copy, nullable) NSIndexSet *acceptableStatusCodes;
80
81 /**
82 The acceptable MIME types for responses. When non-`nil`, responses with a `Content-Type` with MIME types that do not intersect with the set will result in an error during validation.
83 */
84 @property (nonatomic, copy, nullable) NSSet <NSString *> *acceptableContentTypes;
85
86 /**
87 Validates the specified response and data.
88
89 In its base implementation, this method checks for an acceptable status code and content type. Subclasses may wish to add other domain-specific checks.
90
91 @param response The response to be validated.
92 @param data The data associated with the response.
93 @param error The error that occurred while attempting to validate the response.
94
95 @return `YES` if the response is valid, otherwise `NO`.
96 */
97 - (BOOL)validateResponse:(nullable NSHTTPURLResponse *)response
98 data:(nullable NSData *)data
99 error:(NSError * _Nullable __autoreleasing *)error;
100
101 @end
102
103 #pragma mark -
104
105
106 /**
107 `AFJSONResponseSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes JSON responses.
108
109 By default, `AFJSONResponseSerializer` accepts the following MIME types, which includes the official standard, `application/json`, as well as other commonly-used types:
110
111 - `application/json`
112 - `text/json`
113 - `text/javascript`
114 */
115 @interface AFJSONResponseSerializer : AFHTTPResponseSerializer
116
117 - (instancetype)init;
118
119 /**
120 Options for reading the response JSON data and creating the Foundation objects. For possible values, see the `NSJSONSerialization` documentation section "NSJSONReadingOptions". `0` by default.
121 */
122 @property (nonatomic, assign) NSJSONReadingOptions readingOptions;
123
124 /**
125 Whether to remove keys with `NSNull` values from response JSON. Defaults to `NO`.
126 */
127 @property (nonatomic, assign) BOOL removesKeysWithNullValues;
128
129 /**
130 Creates and returns a JSON serializer with specified reading and writing options.
131
132 @param readingOptions The specified JSON reading options.
133 */
134 + (instancetype)serializerWithReadingOptions:(NSJSONReadingOptions)readingOptions;
135
136 @end
137
138 #pragma mark -
139
140 /**
141 `AFXMLParserResponseSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes XML responses as an `NSXMLParser` objects.
142
143 By default, `AFXMLParserResponseSerializer` accepts the following MIME types, which includes the official standard, `application/xml`, as well as other commonly-used types:
144
145 - `application/xml`
146 - `text/xml`
147 */
148 @interface AFXMLParserResponseSerializer : AFHTTPResponseSerializer
149
150 @end
151
152 #pragma mark -
153
154 #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
155
156 /**
157 `AFXMLDocumentResponseSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes XML responses as an `NSXMLDocument` objects.
158
159 By default, `AFXMLDocumentResponseSerializer` accepts the following MIME types, which includes the official standard, `application/xml`, as well as other commonly-used types:
160
161 - `application/xml`
162 - `text/xml`
163 */
164 @interface AFXMLDocumentResponseSerializer : AFHTTPResponseSerializer
165
166 - (instancetype)init;
167
168 /**
169 Input and output options specifically intended for `NSXMLDocument` objects. For possible values, see the `NSJSONSerialization` documentation section "NSJSONReadingOptions". `0` by default.
170 */
171 @property (nonatomic, assign) NSUInteger options;
172
173 /**
174 Creates and returns an XML document serializer with the specified options.
175
176 @param mask The XML document options.
177 */
178 + (instancetype)serializerWithXMLDocumentOptions:(NSUInteger)mask;
179
180 @end
181
182 #endif
183
184 #pragma mark -
185
186 /**
187 `AFPropertyListResponseSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes XML responses as an `NSXMLDocument` objects.
188
189 By default, `AFPropertyListResponseSerializer` accepts the following MIME types:
190
191 - `application/x-plist`
192 */
193 @interface AFPropertyListResponseSerializer : AFHTTPResponseSerializer
194
195 - (instancetype)init;
196
197 /**
198 The property list format. Possible values are described in "NSPropertyListFormat".
199 */
200 @property (nonatomic, assign) NSPropertyListFormat format;
201
202 /**
203 The property list reading options. Possible values are described in "NSPropertyListMutabilityOptions."
204 */
205 @property (nonatomic, assign) NSPropertyListReadOptions readOptions;
206
207 /**
208 Creates and returns a property list serializer with a specified format, read options, and write options.
209
210 @param format The property list format.
211 @param readOptions The property list reading options.
212 */
213 + (instancetype)serializerWithFormat:(NSPropertyListFormat)format
214 readOptions:(NSPropertyListReadOptions)readOptions;
215
216 @end
217
218 #pragma mark -
219
220 /**
221 `AFImageResponseSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes image responses.
222
223 By default, `AFImageResponseSerializer` accepts the following MIME types, which correspond to the image formats supported by UIImage or NSImage:
224
225 - `image/tiff`
226 - `image/jpeg`
227 - `image/gif`
228 - `image/png`
229 - `image/ico`
230 - `image/x-icon`
231 - `image/bmp`
232 - `image/x-bmp`
233 - `image/x-xbitmap`
234 - `image/x-win-bitmap`
235 */
236 @interface AFImageResponseSerializer : AFHTTPResponseSerializer
237
238 #if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
239 /**
240 The scale factor used when interpreting the image data to construct `responseImage`. Specifying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the size property. This is set to the value of scale of the main screen by default, which automatically scales images for retina displays, for instance.
241 */
242 @property (nonatomic, assign) CGFloat imageScale;
243
244 /**
245 Whether to automatically inflate response image data for compressed formats (such as PNG or JPEG). Enabling this can significantly improve drawing performance on iOS when used with `setCompletionBlockWithSuccess:failure:`, as it allows a bitmap representation to be constructed in the background rather than on the main thread. `YES` by default.
246 */
247 @property (nonatomic, assign) BOOL automaticallyInflatesResponseImage;
248 #endif
249
250 @end
251
252 #pragma mark -
253
254 /**
255 `AFCompoundSerializer` is a subclass of `AFHTTPResponseSerializer` that delegates the response serialization to the first `AFHTTPResponseSerializer` object that returns an object for `responseObjectForResponse:data:error:`, falling back on the default behavior of `AFHTTPResponseSerializer`. This is useful for supporting multiple potential types and structures of server responses with a single serializer.
256 */
257 @interface AFCompoundResponseSerializer : AFHTTPResponseSerializer
258
259 /**
260 The component response serializers.
261 */
262 @property (readonly, nonatomic, copy) NSArray <id<AFURLResponseSerialization>> *responseSerializers;
263
264 /**
265 Creates and returns a compound serializer comprised of the specified response serializers.
266
267 @warning Each response serializer specified must be a subclass of `AFHTTPResponseSerializer`, and response to `-validateResponse:data:error:`.
268 */
269 + (instancetype)compoundSerializerWithResponseSerializers:(NSArray <id<AFURLResponseSerialization>> *)responseSerializers;
270
271 @end
272
273 ///----------------
274 /// @name Constants
275 ///----------------
276
277 /**
278 ## Error Domains
279
280 The following error domain is predefined.
281
282 - `NSString * const AFURLResponseSerializationErrorDomain`
283
284 ### Constants
285
286 `AFURLResponseSerializationErrorDomain`
287 AFURLResponseSerializer errors. Error codes for `AFURLResponseSerializationErrorDomain` correspond to codes in `NSURLErrorDomain`.
288 */
289 FOUNDATION_EXPORT NSString * const AFURLResponseSerializationErrorDomain;
290
291 /**
292 ## User info dictionary keys
293
294 These keys may exist in the user info dictionary, in addition to those defined for NSError.
295
296 - `NSString * const AFNetworkingOperationFailingURLResponseErrorKey`
297 - `NSString * const AFNetworkingOperationFailingURLResponseDataErrorKey`
298
299 ### Constants
300
301 `AFNetworkingOperationFailingURLResponseErrorKey`
302 The corresponding value is an `NSURLResponse` containing the response of the operation associated with an error. This key is only present in the `AFURLResponseSerializationErrorDomain`.
303
304 `AFNetworkingOperationFailingURLResponseDataErrorKey`
305 The corresponding value is an `NSData` containing the original data of the operation associated with an error. This key is only present in the `AFURLResponseSerializationErrorDomain`.
306 */
307 FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLResponseErrorKey;
308
309 FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLResponseDataErrorKey;
310
311 NS_ASSUME_NONNULL_END
1 // AFURLResponseSerialization.m
2 // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #import "AFURLResponseSerialization.h"
23
24 #import <TargetConditionals.h>
25
26 #if TARGET_OS_IOS
27 #import <UIKit/UIKit.h>
28 #elif TARGET_OS_WATCH
29 #import <WatchKit/WatchKit.h>
30 #elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
31 #import <Cocoa/Cocoa.h>
32 #endif
33
34 NSString * const AFURLResponseSerializationErrorDomain = @"com.alamofire.error.serialization.response";
35 NSString * const AFNetworkingOperationFailingURLResponseErrorKey = @"com.alamofire.serialization.response.error.response";
36 NSString * const AFNetworkingOperationFailingURLResponseDataErrorKey = @"com.alamofire.serialization.response.error.data";
37
38 static NSError * AFErrorWithUnderlyingError(NSError *error, NSError *underlyingError) {
39 if (!error) {
40 return underlyingError;
41 }
42
43 if (!underlyingError || error.userInfo[NSUnderlyingErrorKey]) {
44 return error;
45 }
46
47 NSMutableDictionary *mutableUserInfo = [error.userInfo mutableCopy];
48 mutableUserInfo[NSUnderlyingErrorKey] = underlyingError;
49
50 return [[NSError alloc] initWithDomain:error.domain code:error.code userInfo:mutableUserInfo];
51 }
52
53 static BOOL AFErrorOrUnderlyingErrorHasCodeInDomain(NSError *error, NSInteger code, NSString *domain) {
54 if ([error.domain isEqualToString:domain] && error.code == code) {
55 return YES;
56 } else if (error.userInfo[NSUnderlyingErrorKey]) {
57 return AFErrorOrUnderlyingErrorHasCodeInDomain(error.userInfo[NSUnderlyingErrorKey], code, domain);
58 }
59
60 return NO;
61 }
62
63 static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingOptions readingOptions) {
64 if ([JSONObject isKindOfClass:[NSArray class]]) {
65 NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:[(NSArray *)JSONObject count]];
66 for (id value in (NSArray *)JSONObject) {
67 [mutableArray addObject:AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions)];
68 }
69
70 return (readingOptions & NSJSONReadingMutableContainers) ? mutableArray : [NSArray arrayWithArray:mutableArray];
71 } else if ([JSONObject isKindOfClass:[NSDictionary class]]) {
72 NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:JSONObject];
73 for (id <NSCopying> key in [(NSDictionary *)JSONObject allKeys]) {
74 id value = (NSDictionary *)JSONObject[key];
75 if (!value || [value isEqual:[NSNull null]]) {
76 [mutableDictionary removeObjectForKey:key];
77 } else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) {
78 mutableDictionary[key] = AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions);
79 }
80 }
81
82 return (readingOptions & NSJSONReadingMutableContainers) ? mutableDictionary : [NSDictionary dictionaryWithDictionary:mutableDictionary];
83 }
84
85 return JSONObject;
86 }
87
88 @implementation AFHTTPResponseSerializer
89
90 + (instancetype)serializer {
91 return [[self alloc] init];
92 }
93
94 - (instancetype)init {
95 self = [super init];
96 if (!self) {
97 return nil;
98 }
99
100 self.stringEncoding = NSUTF8StringEncoding;
101
102 self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
103 self.acceptableContentTypes = nil;
104
105 return self;
106 }
107
108 #pragma mark -
109
110 - (BOOL)validateResponse:(NSHTTPURLResponse *)response
111 data:(NSData *)data
112 error:(NSError * __autoreleasing *)error
113 {
114 BOOL responseIsValid = YES;
115 NSError *validationError = nil;
116
117 if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {
118 if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]] &&
119 !([response MIMEType] == nil && [data length] == 0)) {
120
121 if ([data length] > 0 && [response URL]) {
122 NSMutableDictionary *mutableUserInfo = [@{
123 NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]],
124 NSURLErrorFailingURLErrorKey:[response URL],
125 AFNetworkingOperationFailingURLResponseErrorKey: response,
126 } mutableCopy];
127 if (data) {
128 mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
129 }
130
131 validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:mutableUserInfo], validationError);
132 }
133
134 responseIsValid = NO;
135 }
136
137 if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) {
138 NSMutableDictionary *mutableUserInfo = [@{
139 NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode],
140 NSURLErrorFailingURLErrorKey:[response URL],
141 AFNetworkingOperationFailingURLResponseErrorKey: response,
142 } mutableCopy];
143
144 if (data) {
145 mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
146 }
147
148 validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);
149
150 responseIsValid = NO;
151 }
152 }
153
154 if (error && !responseIsValid) {
155 *error = validationError;
156 }
157
158 return responseIsValid;
159 }
160
161 #pragma mark - AFURLResponseSerialization
162
163 - (id)responseObjectForResponse:(NSURLResponse *)response
164 data:(NSData *)data
165 error:(NSError *__autoreleasing *)error
166 {
167 [self validateResponse:(NSHTTPURLResponse *)response data:data error:error];
168
169 return data;
170 }
171
172 #pragma mark - NSSecureCoding
173
174 + (BOOL)supportsSecureCoding {
175 return YES;
176 }
177
178 - (instancetype)initWithCoder:(NSCoder *)decoder {
179 self = [self init];
180 if (!self) {
181 return nil;
182 }
183
184 self.acceptableStatusCodes = [decoder decodeObjectOfClass:[NSIndexSet class] forKey:NSStringFromSelector(@selector(acceptableStatusCodes))];
185 self.acceptableContentTypes = [decoder decodeObjectOfClass:[NSIndexSet class] forKey:NSStringFromSelector(@selector(acceptableContentTypes))];
186
187 return self;
188 }
189
190 - (void)encodeWithCoder:(NSCoder *)coder {
191 [coder encodeObject:self.acceptableStatusCodes forKey:NSStringFromSelector(@selector(acceptableStatusCodes))];
192 [coder encodeObject:self.acceptableContentTypes forKey:NSStringFromSelector(@selector(acceptableContentTypes))];
193 }
194
195 #pragma mark - NSCopying
196
197 - (instancetype)copyWithZone:(NSZone *)zone {
198 AFHTTPResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
199 serializer.acceptableStatusCodes = [self.acceptableStatusCodes copyWithZone:zone];
200 serializer.acceptableContentTypes = [self.acceptableContentTypes copyWithZone:zone];
201
202 return serializer;
203 }
204
205 @end
206
207 #pragma mark -
208
209 @implementation AFJSONResponseSerializer
210
211 + (instancetype)serializer {
212 return [self serializerWithReadingOptions:(NSJSONReadingOptions)0];
213 }
214
215 + (instancetype)serializerWithReadingOptions:(NSJSONReadingOptions)readingOptions {
216 AFJSONResponseSerializer *serializer = [[self alloc] init];
217 serializer.readingOptions = readingOptions;
218
219 return serializer;
220 }
221
222 - (instancetype)init {
223 self = [super init];
224 if (!self) {
225 return nil;
226 }
227
228 self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil];
229
230 return self;
231 }
232
233 #pragma mark - AFURLResponseSerialization
234
235 - (id)responseObjectForResponse:(NSURLResponse *)response
236 data:(NSData *)data
237 error:(NSError *__autoreleasing *)error
238 {
239 if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
240 if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
241 return nil;
242 }
243 }
244
245 id responseObject = nil;
246 NSError *serializationError = nil;
247 // Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.
248 // See https://github.com/rails/rails/issues/1742
249 BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
250 if (data.length > 0 && !isSpace) {
251 responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
252 } else {
253 return nil;
254 }
255
256 if (self.removesKeysWithNullValues && responseObject) {
257 responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
258 }
259
260 if (error) {
261 *error = AFErrorWithUnderlyingError(serializationError, *error);
262 }
263
264 return responseObject;
265 }
266
267 #pragma mark - NSSecureCoding
268
269 - (instancetype)initWithCoder:(NSCoder *)decoder {
270 self = [super initWithCoder:decoder];
271 if (!self) {
272 return nil;
273 }
274
275 self.readingOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(readingOptions))] unsignedIntegerValue];
276 self.removesKeysWithNullValues = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(removesKeysWithNullValues))] boolValue];
277
278 return self;
279 }
280
281 - (void)encodeWithCoder:(NSCoder *)coder {
282 [super encodeWithCoder:coder];
283
284 [coder encodeObject:@(self.readingOptions) forKey:NSStringFromSelector(@selector(readingOptions))];
285 [coder encodeObject:@(self.removesKeysWithNullValues) forKey:NSStringFromSelector(@selector(removesKeysWithNullValues))];
286 }
287
288 #pragma mark - NSCopying
289
290 - (instancetype)copyWithZone:(NSZone *)zone {
291 AFJSONResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
292 serializer.readingOptions = self.readingOptions;
293 serializer.removesKeysWithNullValues = self.removesKeysWithNullValues;
294
295 return serializer;
296 }
297
298 @end
299
300 #pragma mark -
301
302 @implementation AFXMLParserResponseSerializer
303
304 + (instancetype)serializer {
305 AFXMLParserResponseSerializer *serializer = [[self alloc] init];
306
307 return serializer;
308 }
309
310 - (instancetype)init {
311 self = [super init];
312 if (!self) {
313 return nil;
314 }
315
316 self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"application/xml", @"text/xml", nil];
317
318 return self;
319 }
320
321 #pragma mark - AFURLResponseSerialization
322
323 - (id)responseObjectForResponse:(NSHTTPURLResponse *)response
324 data:(NSData *)data
325 error:(NSError *__autoreleasing *)error
326 {
327 if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
328 if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
329 return nil;
330 }
331 }
332
333 return [[NSXMLParser alloc] initWithData:data];
334 }
335
336 @end
337
338 #pragma mark -
339
340 #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
341
342 @implementation AFXMLDocumentResponseSerializer
343
344 + (instancetype)serializer {
345 return [self serializerWithXMLDocumentOptions:0];
346 }
347
348 + (instancetype)serializerWithXMLDocumentOptions:(NSUInteger)mask {
349 AFXMLDocumentResponseSerializer *serializer = [[self alloc] init];
350 serializer.options = mask;
351
352 return serializer;
353 }
354
355 - (instancetype)init {
356 self = [super init];
357 if (!self) {
358 return nil;
359 }
360
361 self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"application/xml", @"text/xml", nil];
362
363 return self;
364 }
365
366 #pragma mark - AFURLResponseSerialization
367
368 - (id)responseObjectForResponse:(NSURLResponse *)response
369 data:(NSData *)data
370 error:(NSError *__autoreleasing *)error
371 {
372 if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
373 if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
374 return nil;
375 }
376 }
377
378 NSError *serializationError = nil;
379 NSXMLDocument *document = [[NSXMLDocument alloc] initWithData:data options:self.options error:&serializationError];
380
381 if (error) {
382 *error = AFErrorWithUnderlyingError(serializationError, *error);
383 }
384
385 return document;
386 }
387
388 #pragma mark - NSSecureCoding
389
390 - (instancetype)initWithCoder:(NSCoder *)decoder {
391 self = [super initWithCoder:decoder];
392 if (!self) {
393 return nil;
394 }
395
396 self.options = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(options))] unsignedIntegerValue];
397
398 return self;
399 }
400
401 - (void)encodeWithCoder:(NSCoder *)coder {
402 [super encodeWithCoder:coder];
403
404 [coder encodeObject:@(self.options) forKey:NSStringFromSelector(@selector(options))];
405 }
406
407 #pragma mark - NSCopying
408
409 - (instancetype)copyWithZone:(NSZone *)zone {
410 AFXMLDocumentResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
411 serializer.options = self.options;
412
413 return serializer;
414 }
415
416 @end
417
418 #endif
419
420 #pragma mark -
421
422 @implementation AFPropertyListResponseSerializer
423
424 + (instancetype)serializer {
425 return [self serializerWithFormat:NSPropertyListXMLFormat_v1_0 readOptions:0];
426 }
427
428 + (instancetype)serializerWithFormat:(NSPropertyListFormat)format
429 readOptions:(NSPropertyListReadOptions)readOptions
430 {
431 AFPropertyListResponseSerializer *serializer = [[self alloc] init];
432 serializer.format = format;
433 serializer.readOptions = readOptions;
434
435 return serializer;
436 }
437
438 - (instancetype)init {
439 self = [super init];
440 if (!self) {
441 return nil;
442 }
443
444 self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"application/x-plist", nil];
445
446 return self;
447 }
448
449 #pragma mark - AFURLResponseSerialization
450
451 - (id)responseObjectForResponse:(NSURLResponse *)response
452 data:(NSData *)data
453 error:(NSError *__autoreleasing *)error
454 {
455 if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
456 if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
457 return nil;
458 }
459 }
460
461 id responseObject;
462 NSError *serializationError = nil;
463
464 if (data) {
465 responseObject = [NSPropertyListSerialization propertyListWithData:data options:self.readOptions format:NULL error:&serializationError];
466 }
467
468 if (error) {
469 *error = AFErrorWithUnderlyingError(serializationError, *error);
470 }
471
472 return responseObject;
473 }
474
475 #pragma mark - NSSecureCoding
476
477 - (instancetype)initWithCoder:(NSCoder *)decoder {
478 self = [super initWithCoder:decoder];
479 if (!self) {
480 return nil;
481 }
482
483 self.format = (NSPropertyListFormat)[[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(format))] unsignedIntegerValue];
484 self.readOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(readOptions))] unsignedIntegerValue];
485
486 return self;
487 }
488
489 - (void)encodeWithCoder:(NSCoder *)coder {
490 [super encodeWithCoder:coder];
491
492 [coder encodeObject:@(self.format) forKey:NSStringFromSelector(@selector(format))];
493 [coder encodeObject:@(self.readOptions) forKey:NSStringFromSelector(@selector(readOptions))];
494 }
495
496 #pragma mark - NSCopying
497
498 - (instancetype)copyWithZone:(NSZone *)zone {
499 AFPropertyListResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
500 serializer.format = self.format;
501 serializer.readOptions = self.readOptions;
502
503 return serializer;
504 }
505
506 @end
507
508 #pragma mark -
509
510 #if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
511 #import <CoreGraphics/CoreGraphics.h>
512 #import <UIKit/UIKit.h>
513
514 @interface UIImage (AFNetworkingSafeImageLoading)
515 + (UIImage *)af_safeImageWithData:(NSData *)data;
516 @end
517
518 static NSLock* imageLock = nil;
519
520 @implementation UIImage (AFNetworkingSafeImageLoading)
521
522 + (UIImage *)af_safeImageWithData:(NSData *)data {
523 UIImage* image = nil;
524 static dispatch_once_t onceToken;
525 dispatch_once(&onceToken, ^{
526 imageLock = [[NSLock alloc] init];
527 });
528
529 [imageLock lock];
530 image = [UIImage imageWithData:data];
531 [imageLock unlock];
532 return image;
533 }
534
535 @end
536
537 static UIImage * AFImageWithDataAtScale(NSData *data, CGFloat scale) {
538 UIImage *image = [UIImage af_safeImageWithData:data];
539 if (image.images) {
540 return image;
541 }
542
543 return [[UIImage alloc] initWithCGImage:[image CGImage] scale:scale orientation:image.imageOrientation];
544 }
545
546 static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *response, NSData *data, CGFloat scale) {
547 if (!data || [data length] == 0) {
548 return nil;
549 }
550
551 CGImageRef imageRef = NULL;
552 CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
553
554 if ([response.MIMEType isEqualToString:@"image/png"]) {
555 imageRef = CGImageCreateWithPNGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault);
556 } else if ([response.MIMEType isEqualToString:@"image/jpeg"]) {
557 imageRef = CGImageCreateWithJPEGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault);
558
559 if (imageRef) {
560 CGColorSpaceRef imageColorSpace = CGImageGetColorSpace(imageRef);
561 CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(imageColorSpace);
562
563 // CGImageCreateWithJPEGDataProvider does not properly handle CMKY, so fall back to AFImageWithDataAtScale
564 if (imageColorSpaceModel == kCGColorSpaceModelCMYK) {
565 CGImageRelease(imageRef);
566 imageRef = NULL;
567 }
568 }
569 }
570
571 CGDataProviderRelease(dataProvider);
572
573 UIImage *image = AFImageWithDataAtScale(data, scale);
574 if (!imageRef) {
575 if (image.images || !image) {
576 return image;
577 }
578
579 imageRef = CGImageCreateCopy([image CGImage]);
580 if (!imageRef) {
581 return nil;
582 }
583 }
584
585 size_t width = CGImageGetWidth(imageRef);
586 size_t height = CGImageGetHeight(imageRef);
587 size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef);
588
589 if (width * height > 1024 * 1024 || bitsPerComponent > 8) {
590 CGImageRelease(imageRef);
591
592 return image;
593 }
594
595 // CGImageGetBytesPerRow() calculates incorrectly in iOS 5.0, so defer to CGBitmapContextCreate
596 size_t bytesPerRow = 0;
597 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
598 CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);
599 CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
600
601 if (colorSpaceModel == kCGColorSpaceModelRGB) {
602 uint32_t alpha = (bitmapInfo & kCGBitmapAlphaInfoMask);
603 #pragma clang diagnostic push
604 #pragma clang diagnostic ignored "-Wassign-enum"
605 if (alpha == kCGImageAlphaNone) {
606 bitmapInfo &= ~kCGBitmapAlphaInfoMask;
607 bitmapInfo |= kCGImageAlphaNoneSkipFirst;
608 } else if (!(alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast)) {
609 bitmapInfo &= ~kCGBitmapAlphaInfoMask;
610 bitmapInfo |= kCGImageAlphaPremultipliedFirst;
611 }
612 #pragma clang diagnostic pop
613 }
614
615 CGContextRef context = CGBitmapContextCreate(NULL, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);
616
617 CGColorSpaceRelease(colorSpace);
618
619 if (!context) {
620 CGImageRelease(imageRef);
621
622 return image;
623 }
624
625 CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), imageRef);
626 CGImageRef inflatedImageRef = CGBitmapContextCreateImage(context);
627
628 CGContextRelease(context);
629
630 UIImage *inflatedImage = [[UIImage alloc] initWithCGImage:inflatedImageRef scale:scale orientation:image.imageOrientation];
631
632 CGImageRelease(inflatedImageRef);
633 CGImageRelease(imageRef);
634
635 return inflatedImage;
636 }
637 #endif
638
639
640 @implementation AFImageResponseSerializer
641
642 - (instancetype)init {
643 self = [super init];
644 if (!self) {
645 return nil;
646 }
647
648 self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap", nil];
649
650 #if TARGET_OS_IOS || TARGET_OS_TV
651 self.imageScale = [[UIScreen mainScreen] scale];
652 self.automaticallyInflatesResponseImage = YES;
653 #elif TARGET_OS_WATCH
654 self.imageScale = [[WKInterfaceDevice currentDevice] screenScale];
655 self.automaticallyInflatesResponseImage = YES;
656 #endif
657
658 return self;
659 }
660
661 #pragma mark - AFURLResponseSerializer
662
663 - (id)responseObjectForResponse:(NSURLResponse *)response
664 data:(NSData *)data
665 error:(NSError *__autoreleasing *)error
666 {
667 if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
668 if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
669 return nil;
670 }
671 }
672
673 #if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
674 if (self.automaticallyInflatesResponseImage) {
675 return AFInflatedImageFromResponseWithDataAtScale((NSHTTPURLResponse *)response, data, self.imageScale);
676 } else {
677 return AFImageWithDataAtScale(data, self.imageScale);
678 }
679 #else
680 // Ensure that the image is set to it's correct pixel width and height
681 NSBitmapImageRep *bitimage = [[NSBitmapImageRep alloc] initWithData:data];
682 NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize([bitimage pixelsWide], [bitimage pixelsHigh])];
683 [image addRepresentation:bitimage];
684
685 return image;
686 #endif
687
688 return nil;
689 }
690
691 #pragma mark - NSSecureCoding
692
693 - (instancetype)initWithCoder:(NSCoder *)decoder {
694 self = [super initWithCoder:decoder];
695 if (!self) {
696 return nil;
697 }
698
699 #if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
700 NSNumber *imageScale = [decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(imageScale))];
701 #if CGFLOAT_IS_DOUBLE
702 self.imageScale = [imageScale doubleValue];
703 #else
704 self.imageScale = [imageScale floatValue];
705 #endif
706
707 self.automaticallyInflatesResponseImage = [decoder decodeBoolForKey:NSStringFromSelector(@selector(automaticallyInflatesResponseImage))];
708 #endif
709
710 return self;
711 }
712
713 - (void)encodeWithCoder:(NSCoder *)coder {
714 [super encodeWithCoder:coder];
715
716 #if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
717 [coder encodeObject:@(self.imageScale) forKey:NSStringFromSelector(@selector(imageScale))];
718 [coder encodeBool:self.automaticallyInflatesResponseImage forKey:NSStringFromSelector(@selector(automaticallyInflatesResponseImage))];
719 #endif
720 }
721
722 #pragma mark - NSCopying
723
724 - (instancetype)copyWithZone:(NSZone *)zone {
725 AFImageResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
726
727 #if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
728 serializer.imageScale = self.imageScale;
729 serializer.automaticallyInflatesResponseImage = self.automaticallyInflatesResponseImage;
730 #endif
731
732 return serializer;
733 }
734
735 @end
736
737 #pragma mark -
738
739 @interface AFCompoundResponseSerializer ()
740 @property (readwrite, nonatomic, copy) NSArray *responseSerializers;
741 @end
742
743 @implementation AFCompoundResponseSerializer
744
745 + (instancetype)compoundSerializerWithResponseSerializers:(NSArray *)responseSerializers {
746 AFCompoundResponseSerializer *serializer = [[self alloc] init];
747 serializer.responseSerializers = responseSerializers;
748
749 return serializer;
750 }
751
752 #pragma mark - AFURLResponseSerialization
753
754 - (id)responseObjectForResponse:(NSURLResponse *)response
755 data:(NSData *)data
756 error:(NSError *__autoreleasing *)error
757 {
758 for (id <AFURLResponseSerialization> serializer in self.responseSerializers) {
759 if (![serializer isKindOfClass:[AFHTTPResponseSerializer class]]) {
760 continue;
761 }
762
763 NSError *serializerError = nil;
764 id responseObject = [serializer responseObjectForResponse:response data:data error:&serializerError];
765 if (responseObject) {
766 if (error) {
767 *error = AFErrorWithUnderlyingError(serializerError, *error);
768 }
769
770 return responseObject;
771 }
772 }
773
774 return [super responseObjectForResponse:response data:data error:error];
775 }
776
777 #pragma mark - NSSecureCoding
778
779 - (instancetype)initWithCoder:(NSCoder *)decoder {
780 self = [super initWithCoder:decoder];
781 if (!self) {
782 return nil;
783 }
784
785 self.responseSerializers = [decoder decodeObjectOfClass:[NSArray class] forKey:NSStringFromSelector(@selector(responseSerializers))];
786
787 return self;
788 }
789
790 - (void)encodeWithCoder:(NSCoder *)coder {
791 [super encodeWithCoder:coder];
792
793 [coder encodeObject:self.responseSerializers forKey:NSStringFromSelector(@selector(responseSerializers))];
794 }
795
796 #pragma mark - NSCopying
797
798 - (instancetype)copyWithZone:(NSZone *)zone {
799 AFCompoundResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
800 serializer.responseSerializers = self.responseSerializers;
801
802 return serializer;
803 }
804
805 @end
1 // AFURLSessionManager.h
2 // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22
23 #import <Foundation/Foundation.h>
24
25 #import "AFURLResponseSerialization.h"
26 #import "AFURLRequestSerialization.h"
27 #import "AFSecurityPolicy.h"
28 #if !TARGET_OS_WATCH
29 #import "AFNetworkReachabilityManager.h"
30 #endif
31
32 /**
33 `AFURLSessionManager` creates and manages an `NSURLSession` object based on a specified `NSURLSessionConfiguration` object, which conforms to `<NSURLSessionTaskDelegate>`, `<NSURLSessionDataDelegate>`, `<NSURLSessionDownloadDelegate>`, and `<NSURLSessionDelegate>`.
34
35 ## Subclassing Notes
36
37 This is the base class for `AFHTTPSessionManager`, which adds functionality specific to making HTTP requests. If you are looking to extend `AFURLSessionManager` specifically for HTTP, consider subclassing `AFHTTPSessionManager` instead.
38
39 ## NSURLSession & NSURLSessionTask Delegate Methods
40
41 `AFURLSessionManager` implements the following delegate methods:
42
43 ### `NSURLSessionDelegate`
44
45 - `URLSession:didBecomeInvalidWithError:`
46 - `URLSession:didReceiveChallenge:completionHandler:`
47 - `URLSessionDidFinishEventsForBackgroundURLSession:`
48
49 ### `NSURLSessionTaskDelegate`
50
51 - `URLSession:willPerformHTTPRedirection:newRequest:completionHandler:`
52 - `URLSession:task:didReceiveChallenge:completionHandler:`
53 - `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:`
54 - `URLSession:task:needNewBodyStream:`
55 - `URLSession:task:didCompleteWithError:`
56
57 ### `NSURLSessionDataDelegate`
58
59 - `URLSession:dataTask:didReceiveResponse:completionHandler:`
60 - `URLSession:dataTask:didBecomeDownloadTask:`
61 - `URLSession:dataTask:didReceiveData:`
62 - `URLSession:dataTask:willCacheResponse:completionHandler:`
63
64 ### `NSURLSessionDownloadDelegate`
65
66 - `URLSession:downloadTask:didFinishDownloadingToURL:`
67 - `URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesWritten:totalBytesExpectedToWrite:`
68 - `URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:`
69
70 If any of these methods are overridden in a subclass, they _must_ call the `super` implementation first.
71
72 ## Network Reachability Monitoring
73
74 Network reachability status and change monitoring is available through the `reachabilityManager` property. Applications may choose to monitor network reachability conditions in order to prevent or suspend any outbound requests. See `AFNetworkReachabilityManager` for more details.
75
76 ## NSCoding Caveats
77
78 - Encoded managers do not include any block properties. Be sure to set delegate callback blocks when using `-initWithCoder:` or `NSKeyedUnarchiver`.
79
80 ## NSCopying Caveats
81
82 - `-copy` and `-copyWithZone:` return a new manager with a new `NSURLSession` created from the configuration of the original.
83 - Operation copies do not include any delegate callback blocks, as they often strongly captures a reference to `self`, which would otherwise have the unintuitive side-effect of pointing to the _original_ session manager when copied.
84
85 @warning Managers for background sessions must be owned for the duration of their use. This can be accomplished by creating an application-wide or shared singleton instance.
86 */
87
88 NS_ASSUME_NONNULL_BEGIN
89
90 @interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>
91
92 /**
93 The managed session.
94 */
95 @property (readonly, nonatomic, strong) NSURLSession *session;
96
97 /**
98 The operation queue on which delegate callbacks are run.
99 */
100 @property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;
101
102 /**
103 Responses sent from the server in data tasks created with `dataTaskWithRequest:success:failure:` and run using the `GET` / `POST` / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to an instance of `AFJSONResponseSerializer`.
104
105 @warning `responseSerializer` must not be `nil`.
106 */
107 @property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer;
108
109 ///-------------------------------
110 /// @name Managing Security Policy
111 ///-------------------------------
112
113 /**
114 The security policy used by created session to evaluate server trust for secure connections. `AFURLSessionManager` uses the `defaultPolicy` unless otherwise specified.
115 */
116 @property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
117
118 #if !TARGET_OS_WATCH
119 ///--------------------------------------
120 /// @name Monitoring Network Reachability
121 ///--------------------------------------
122
123 /**
124 The network reachability manager. `AFURLSessionManager` uses the `sharedManager` by default.
125 */
126 @property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;
127 #endif
128
129 ///----------------------------
130 /// @name Getting Session Tasks
131 ///----------------------------
132
133 /**
134 The data, upload, and download tasks currently run by the managed session.
135 */
136 @property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;
137
138 /**
139 The data tasks currently run by the managed session.
140 */
141 @property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;
142
143 /**
144 The upload tasks currently run by the managed session.
145 */
146 @property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;
147
148 /**
149 The download tasks currently run by the managed session.
150 */
151 @property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;
152
153 ///-------------------------------
154 /// @name Managing Callback Queues
155 ///-------------------------------
156
157 /**
158 The dispatch queue for `completionBlock`. If `NULL` (default), the main queue is used.
159 */
160 @property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;
161
162 /**
163 The dispatch group for `completionBlock`. If `NULL` (default), a private dispatch group is used.
164 */
165 @property (nonatomic, strong, nullable) dispatch_group_t completionGroup;
166
167 ///---------------------------------
168 /// @name Working Around System Bugs
169 ///---------------------------------
170
171 /**
172 Whether to attempt to retry creation of upload tasks for background sessions when initial call returns `nil`. `NO` by default.
173
174 @bug As of iOS 7.0, there is a bug where upload tasks created for background tasks are sometimes `nil`. As a workaround, if this property is `YES`, AFNetworking will follow Apple's recommendation to try creating the task again.
175
176 @see https://github.com/AFNetworking/AFNetworking/issues/1675
177 */
178 @property (nonatomic, assign) BOOL attemptsToRecreateUploadTasksForBackgroundSessions;
179
180 ///---------------------
181 /// @name Initialization
182 ///---------------------
183
184 /**
185 Creates and returns a manager for a session created with the specified configuration. This is the designated initializer.
186
187 @param configuration The configuration used to create the managed session.
188
189 @return A manager for a newly-created session.
190 */
191 - (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
192
193 /**
194 Invalidates the managed session, optionally canceling pending tasks.
195
196 @param cancelPendingTasks Whether or not to cancel pending tasks.
197 */
198 - (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks;
199
200 ///-------------------------
201 /// @name Running Data Tasks
202 ///-------------------------
203
204 /**
205 Creates an `NSURLSessionDataTask` with the specified request.
206
207 @param request The HTTP request for the request.
208 @param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
209 */
210 - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
211 completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler DEPRECATED_ATTRIBUTE;
212
213 /**
214 Creates an `NSURLSessionDataTask` with the specified request.
215
216 @param request The HTTP request for the request.
217 @param uploadProgressBlock A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
218 @param downloadProgressBlock A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue.
219 @param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
220 */
221 - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
222 uploadProgress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
223 downloadProgress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
224 completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
225
226 ///---------------------------
227 /// @name Running Upload Tasks
228 ///---------------------------
229
230 /**
231 Creates an `NSURLSessionUploadTask` with the specified request for a local file.
232
233 @param request The HTTP request for the request.
234 @param fileURL A URL to the local file to be uploaded.
235 @param uploadProgressBlock A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
236 @param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
237
238 @see `attemptsToRecreateUploadTasksForBackgroundSessions`
239 */
240 - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
241 fromFile:(NSURL *)fileURL
242 progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
243 completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
244
245 /**
246 Creates an `NSURLSessionUploadTask` with the specified request for an HTTP body.
247
248 @param request The HTTP request for the request.
249 @param bodyData A data object containing the HTTP body to be uploaded.
250 @param uploadProgressBlock A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
251 @param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
252 */
253 - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
254 fromData:(nullable NSData *)bodyData
255 progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
256 completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
257
258 /**
259 Creates an `NSURLSessionUploadTask` with the specified streaming request.
260
261 @param request The HTTP request for the request.
262 @param uploadProgressBlock A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
263 @param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
264 */
265 - (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
266 progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
267 completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
268
269 ///-----------------------------
270 /// @name Running Download Tasks
271 ///-----------------------------
272
273 /**
274 Creates an `NSURLSessionDownloadTask` with the specified request.
275
276 @param request The HTTP request for the request.
277 @param downloadProgressBlock A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue.
278 @param destination A block object to be executed in order to determine the destination of the downloaded file. This block takes two arguments, the target path & the server response, and returns the desired file URL of the resulting download. The temporary file used during the download will be automatically deleted after being moved to the returned URL.
279 @param completionHandler A block to be executed when a task finishes. This block has no return value and takes three arguments: the server response, the path of the downloaded file, and the error describing the network or parsing error that occurred, if any.
280
281 @warning If using a background `NSURLSessionConfiguration` on iOS, these blocks will be lost when the app is terminated. Background sessions may prefer to use `-setDownloadTaskDidFinishDownloadingBlock:` to specify the URL for saving the downloaded file, rather than the destination block of this method.
282 */
283 - (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
284 progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
285 destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
286 completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;
287
288 /**
289 Creates an `NSURLSessionDownloadTask` with the specified resume data.
290
291 @param resumeData The data used to resume downloading.
292 @param downloadProgressBlock A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue.
293 @param destination A block object to be executed in order to determine the destination of the downloaded file. This block takes two arguments, the target path & the server response, and returns the desired file URL of the resulting download. The temporary file used during the download will be automatically deleted after being moved to the returned URL.
294 @param completionHandler A block to be executed when a task finishes. This block has no return value and takes three arguments: the server response, the path of the downloaded file, and the error describing the network or parsing error that occurred, if any.
295 */
296 - (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
297 progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
298 destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
299 completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;
300
301 ///---------------------------------
302 /// @name Getting Progress for Tasks
303 ///---------------------------------
304
305 /**
306 Returns the upload progress of the specified task.
307
308 @param task The session task. Must not be `nil`.
309
310 @return An `NSProgress` object reporting the upload progress of a task, or `nil` if the progress is unavailable.
311 */
312 - (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;
313
314 /**
315 Returns the download progress of the specified task.
316
317 @param task The session task. Must not be `nil`.
318
319 @return An `NSProgress` object reporting the download progress of a task, or `nil` if the progress is unavailable.
320 */
321 - (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;
322
323 ///-----------------------------------------
324 /// @name Setting Session Delegate Callbacks
325 ///-----------------------------------------
326
327 /**
328 Sets a block to be executed when the managed session becomes invalid, as handled by the `NSURLSessionDelegate` method `URLSession:didBecomeInvalidWithError:`.
329
330 @param block A block object to be executed when the managed session becomes invalid. The block has no return value, and takes two arguments: the session, and the error related to the cause of invalidation.
331 */
332 - (void)setSessionDidBecomeInvalidBlock:(nullable void (^)(NSURLSession *session, NSError *error))block;
333
334 /**
335 Sets a block to be executed when a connection level authentication challenge has occurred, as handled by the `NSURLSessionDelegate` method `URLSession:didReceiveChallenge:completionHandler:`.
336
337 @param block A block object to be executed when a connection level authentication challenge has occurred. The block returns the disposition of the authentication challenge, and takes three arguments: the session, the authentication challenge, and a pointer to the credential that should be used to resolve the challenge.
338 */
339 - (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;
340
341 ///--------------------------------------
342 /// @name Setting Task Delegate Callbacks
343 ///--------------------------------------
344
345 /**
346 Sets a block to be executed when a task requires a new request body stream to send to the remote server, as handled by the `NSURLSessionTaskDelegate` method `URLSession:task:needNewBodyStream:`.
347
348 @param block A block object to be executed when a task requires a new request body stream.
349 */
350 - (void)setTaskNeedNewBodyStreamBlock:(nullable NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block;
351
352 /**
353 Sets a block to be executed when an HTTP request is attempting to perform a redirection to a different URL, as handled by the `NSURLSessionTaskDelegate` method `URLSession:willPerformHTTPRedirection:newRequest:completionHandler:`.
354
355 @param block A block object to be executed when an HTTP request is attempting to perform a redirection to a different URL. The block returns the request to be made for the redirection, and takes four arguments: the session, the task, the redirection response, and the request corresponding to the redirection response.
356 */
357 - (void)setTaskWillPerformHTTPRedirectionBlock:(nullable NSURLRequest * (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block;
358
359 /**
360 Sets a block to be executed when a session task has received a request specific authentication challenge, as handled by the `NSURLSessionTaskDelegate` method `URLSession:task:didReceiveChallenge:completionHandler:`.
361
362 @param block A block object to be executed when a session task has received a request specific authentication challenge. The block returns the disposition of the authentication challenge, and takes four arguments: the session, the task, the authentication challenge, and a pointer to the credential that should be used to resolve the challenge.
363 */
364 - (void)setTaskDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;
365
366 /**
367 Sets a block to be executed periodically to track upload progress, as handled by the `NSURLSessionTaskDelegate` method `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:`.
368
369 @param block A block object to be called when an undetermined number of bytes have been uploaded to the server. This block has no return value and takes five arguments: the session, the task, the number of bytes written since the last time the upload progress block was called, the total bytes written, and the total bytes expected to be written during the request, as initially determined by the length of the HTTP body. This block may be called multiple times, and will execute on the main thread.
370 */
371 - (void)setTaskDidSendBodyDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block;
372
373 /**
374 Sets a block to be executed as the last message related to a specific task, as handled by the `NSURLSessionTaskDelegate` method `URLSession:task:didCompleteWithError:`.
375
376 @param block A block object to be executed when a session task is completed. The block has no return value, and takes three arguments: the session, the task, and any error that occurred in the process of executing the task.
377 */
378 - (void)setTaskDidCompleteBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, NSError * _Nullable error))block;
379
380 ///-------------------------------------------
381 /// @name Setting Data Task Delegate Callbacks
382 ///-------------------------------------------
383
384 /**
385 Sets a block to be executed when a data task has received a response, as handled by the `NSURLSessionDataDelegate` method `URLSession:dataTask:didReceiveResponse:completionHandler:`.
386
387 @param block A block object to be executed when a data task has received a response. The block returns the disposition of the session response, and takes three arguments: the session, the data task, and the received response.
388 */
389 - (void)setDataTaskDidReceiveResponseBlock:(nullable NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block;
390
391 /**
392 Sets a block to be executed when a data task has become a download task, as handled by the `NSURLSessionDataDelegate` method `URLSession:dataTask:didBecomeDownloadTask:`.
393
394 @param block A block object to be executed when a data task has become a download task. The block has no return value, and takes three arguments: the session, the data task, and the download task it has become.
395 */
396 - (void)setDataTaskDidBecomeDownloadTaskBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block;
397
398 /**
399 Sets a block to be executed when a data task receives data, as handled by the `NSURLSessionDataDelegate` method `URLSession:dataTask:didReceiveData:`.
400
401 @param block A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the session, the data task, and the data received. This block may be called multiple times, and will execute on the session manager operation queue.
402 */
403 - (void)setDataTaskDidReceiveDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block;
404
405 /**
406 Sets a block to be executed to determine the caching behavior of a data task, as handled by the `NSURLSessionDataDelegate` method `URLSession:dataTask:willCacheResponse:completionHandler:`.
407
408 @param block A block object to be executed to determine the caching behavior of a data task. The block returns the response to cache, and takes three arguments: the session, the data task, and the proposed cached URL response.
409 */
410 - (void)setDataTaskWillCacheResponseBlock:(nullable NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block;
411
412 /**
413 Sets a block to be executed once all messages enqueued for a session have been delivered, as handled by the `NSURLSessionDataDelegate` method `URLSessionDidFinishEventsForBackgroundURLSession:`.
414
415 @param block A block object to be executed once all messages enqueued for a session have been delivered. The block has no return value and takes a single argument: the session.
416 */
417 - (void)setDidFinishEventsForBackgroundURLSessionBlock:(nullable void (^)(NSURLSession *session))block;
418
419 ///-----------------------------------------------
420 /// @name Setting Download Task Delegate Callbacks
421 ///-----------------------------------------------
422
423 /**
424 Sets a block to be executed when a download task has completed a download, as handled by the `NSURLSessionDownloadDelegate` method `URLSession:downloadTask:didFinishDownloadingToURL:`.
425
426 @param block A block object to be executed when a download task has completed. The block returns the URL the download should be moved to, and takes three arguments: the session, the download task, and the temporary location of the downloaded file. If the file manager encounters an error while attempting to move the temporary file to the destination, an `AFURLSessionDownloadTaskDidFailToMoveFileNotification` will be posted, with the download task as its object, and the user info of the error.
427 */
428 - (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * _Nullable (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block;
429
430 /**
431 Sets a block to be executed periodically to track download progress, as handled by the `NSURLSessionDownloadDelegate` method `URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesWritten:totalBytesExpectedToWrite:`.
432
433 @param block A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes five arguments: the session, the download task, the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times, and will execute on the session manager operation queue.
434 */
435 - (void)setDownloadTaskDidWriteDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block;
436
437 /**
438 Sets a block to be executed when a download task has been resumed, as handled by the `NSURLSessionDownloadDelegate` method `URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:`.
439
440 @param block A block object to be executed when a download task has been resumed. The block has no return value and takes four arguments: the session, the download task, the file offset of the resumed download, and the total number of bytes expected to be downloaded.
441 */
442 - (void)setDownloadTaskDidResumeBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block;
443
444 @end
445
446 ///--------------------
447 /// @name Notifications
448 ///--------------------
449
450 /**
451 Posted when a task resumes.
452 */
453 FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidResumeNotification;
454
455 /**
456 Posted when a task finishes executing. Includes a userInfo dictionary with additional information about the task.
457 */
458 FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteNotification;
459
460 /**
461 Posted when a task suspends its execution.
462 */
463 FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidSuspendNotification;
464
465 /**
466 Posted when a session is invalidated.
467 */
468 FOUNDATION_EXPORT NSString * const AFURLSessionDidInvalidateNotification;
469
470 /**
471 Posted when a session download task encountered an error when moving the temporary download file to a specified destination.
472 */
473 FOUNDATION_EXPORT NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification;
474
475 /**
476 The raw response data of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if response data exists for the task.
477 */
478 FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteResponseDataKey;
479
480 /**
481 The serialized response object of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if the response was serialized.
482 */
483 FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey;
484
485 /**
486 The response serializer used to serialize the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if the task has an associated response serializer.
487 */
488 FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey;
489
490 /**
491 The file path associated with the download task. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if an the response data has been stored directly to disk.
492 */
493 FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteAssetPathKey;
494
495 /**
496 Any error associated with the task, or the serialization of the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if an error exists.
497 */
498 FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteErrorKey;
499
500 NS_ASSUME_NONNULL_END
1 // AFURLSessionManager.m
2 // Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #import "AFURLSessionManager.h"
23 #import <objc/runtime.h>
24
25 #ifndef NSFoundationVersionNumber_iOS_8_0
26 #define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug 1140.11
27 #else
28 #define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug NSFoundationVersionNumber_iOS_8_0
29 #endif
30
31 static dispatch_queue_t url_session_manager_creation_queue() {
32 static dispatch_queue_t af_url_session_manager_creation_queue;
33 static dispatch_once_t onceToken;
34 dispatch_once(&onceToken, ^{
35 af_url_session_manager_creation_queue = dispatch_queue_create("com.alamofire.networking.session.manager.creation", DISPATCH_QUEUE_SERIAL);
36 });
37
38 return af_url_session_manager_creation_queue;
39 }
40
41 static void url_session_manager_create_task_safely(dispatch_block_t block) {
42 if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) {
43 // Fix of bug
44 // Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8)
45 // Issue about:https://github.com/AFNetworking/AFNetworking/issues/2093
46 dispatch_sync(url_session_manager_creation_queue(), block);
47 } else {
48 block();
49 }
50 }
51
52 static dispatch_queue_t url_session_manager_processing_queue() {
53 static dispatch_queue_t af_url_session_manager_processing_queue;
54 static dispatch_once_t onceToken;
55 dispatch_once(&onceToken, ^{
56 af_url_session_manager_processing_queue = dispatch_queue_create("com.alamofire.networking.session.manager.processing", DISPATCH_QUEUE_CONCURRENT);
57 });
58
59 return af_url_session_manager_processing_queue;
60 }
61
62 static dispatch_group_t url_session_manager_completion_group() {
63 static dispatch_group_t af_url_session_manager_completion_group;
64 static dispatch_once_t onceToken;
65 dispatch_once(&onceToken, ^{
66 af_url_session_manager_completion_group = dispatch_group_create();
67 });
68
69 return af_url_session_manager_completion_group;
70 }
71
72 NSString * const AFNetworkingTaskDidResumeNotification = @"com.alamofire.networking.task.resume";
73 NSString * const AFNetworkingTaskDidCompleteNotification = @"com.alamofire.networking.task.complete";
74 NSString * const AFNetworkingTaskDidSuspendNotification = @"com.alamofire.networking.task.suspend";
75 NSString * const AFURLSessionDidInvalidateNotification = @"com.alamofire.networking.session.invalidate";
76 NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification = @"com.alamofire.networking.session.download.file-manager-error";
77
78 NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey = @"com.alamofire.networking.task.complete.serializedresponse";
79 NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey = @"com.alamofire.networking.task.complete.responseserializer";
80 NSString * const AFNetworkingTaskDidCompleteResponseDataKey = @"com.alamofire.networking.complete.finish.responsedata";
81 NSString * const AFNetworkingTaskDidCompleteErrorKey = @"com.alamofire.networking.task.complete.error";
82 NSString * const AFNetworkingTaskDidCompleteAssetPathKey = @"com.alamofire.networking.task.complete.assetpath";
83
84 static NSString * const AFURLSessionManagerLockName = @"com.alamofire.networking.session.manager.lock";
85
86 static NSUInteger const AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask = 3;
87
88 typedef void (^AFURLSessionDidBecomeInvalidBlock)(NSURLSession *session, NSError *error);
89 typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential);
90
91 typedef NSURLRequest * (^AFURLSessionTaskWillPerformHTTPRedirectionBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request);
92 typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionTaskDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential);
93 typedef void (^AFURLSessionDidFinishEventsForBackgroundURLSessionBlock)(NSURLSession *session);
94
95 typedef NSInputStream * (^AFURLSessionTaskNeedNewBodyStreamBlock)(NSURLSession *session, NSURLSessionTask *task);
96 typedef void (^AFURLSessionTaskDidSendBodyDataBlock)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend);
97 typedef void (^AFURLSessionTaskDidCompleteBlock)(NSURLSession *session, NSURLSessionTask *task, NSError *error);
98
99 typedef NSURLSessionResponseDisposition (^AFURLSessionDataTaskDidReceiveResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response);
100 typedef void (^AFURLSessionDataTaskDidBecomeDownloadTaskBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask);
101 typedef void (^AFURLSessionDataTaskDidReceiveDataBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data);
102 typedef NSCachedURLResponse * (^AFURLSessionDataTaskWillCacheResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse);
103
104 typedef NSURL * (^AFURLSessionDownloadTaskDidFinishDownloadingBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location);
105 typedef void (^AFURLSessionDownloadTaskDidWriteDataBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite);
106 typedef void (^AFURLSessionDownloadTaskDidResumeBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes);
107 typedef void (^AFURLSessionTaskProgressBlock)(NSProgress *);
108
109 typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id responseObject, NSError *error);
110
111
112 #pragma mark -
113
114 @interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
115 @property (nonatomic, weak) AFURLSessionManager *manager;
116 @property (nonatomic, strong) NSMutableData *mutableData;
117 @property (nonatomic, strong) NSProgress *uploadProgress;
118 @property (nonatomic, strong) NSProgress *downloadProgress;
119 @property (nonatomic, copy) NSURL *downloadFileURL;
120 @property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
121 @property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;
122 @property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;
123 @property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;
124 @end
125
126 @implementation AFURLSessionManagerTaskDelegate
127
128 - (instancetype)init {
129 self = [super init];
130 if (!self) {
131 return nil;
132 }
133
134 self.mutableData = [NSMutableData data];
135 self.uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
136 self.uploadProgress.totalUnitCount = NSURLSessionTransferSizeUnknown;
137
138 self.downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
139 self.downloadProgress.totalUnitCount = NSURLSessionTransferSizeUnknown;
140 return self;
141 }
142
143 #pragma mark - NSProgress Tracking
144
145 - (void)setupProgressForTask:(NSURLSessionTask *)task {
146 __weak __typeof__(task) weakTask = task;
147
148 self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
149 self.downloadProgress.totalUnitCount = task.countOfBytesExpectedToReceive;
150 [self.uploadProgress setCancellable:YES];
151 [self.uploadProgress setCancellationHandler:^{
152 __typeof__(weakTask) strongTask = weakTask;
153 [strongTask cancel];
154 }];
155 [self.uploadProgress setPausable:YES];
156 [self.uploadProgress setPausingHandler:^{
157 __typeof__(weakTask) strongTask = weakTask;
158 [strongTask suspend];
159 }];
160 if ([self.uploadProgress respondsToSelector:@selector(setResumingHandler:)]) {
161 [self.uploadProgress setResumingHandler:^{
162 __typeof__(weakTask) strongTask = weakTask;
163 [strongTask resume];
164 }];
165 }
166
167 [self.downloadProgress setCancellable:YES];
168 [self.downloadProgress setCancellationHandler:^{
169 __typeof__(weakTask) strongTask = weakTask;
170 [strongTask cancel];
171 }];
172 [self.downloadProgress setPausable:YES];
173 [self.downloadProgress setPausingHandler:^{
174 __typeof__(weakTask) strongTask = weakTask;
175 [strongTask suspend];
176 }];
177
178 if ([self.downloadProgress respondsToSelector:@selector(setResumingHandler:)]) {
179 [self.downloadProgress setResumingHandler:^{
180 __typeof__(weakTask) strongTask = weakTask;
181 [strongTask resume];
182 }];
183 }
184
185 [task addObserver:self
186 forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))
187 options:NSKeyValueObservingOptionNew
188 context:NULL];
189 [task addObserver:self
190 forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))
191 options:NSKeyValueObservingOptionNew
192 context:NULL];
193
194 [task addObserver:self
195 forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))
196 options:NSKeyValueObservingOptionNew
197 context:NULL];
198 [task addObserver:self
199 forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))
200 options:NSKeyValueObservingOptionNew
201 context:NULL];
202
203 [self.downloadProgress addObserver:self
204 forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
205 options:NSKeyValueObservingOptionNew
206 context:NULL];
207 [self.uploadProgress addObserver:self
208 forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
209 options:NSKeyValueObservingOptionNew
210 context:NULL];
211 }
212
213 - (void)cleanUpProgressForTask:(NSURLSessionTask *)task {
214 [task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))];
215 [task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))];
216 [task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))];
217 [task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))];
218 [self.downloadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
219 [self.uploadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
220 }
221
222 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
223 if ([object isKindOfClass:[NSURLSessionTask class]] || [object isKindOfClass:[NSURLSessionDownloadTask class]]) {
224 if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) {
225 self.downloadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
226 } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))]) {
227 self.downloadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
228 } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
229 self.uploadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
230 } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToSend))]) {
231 self.uploadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
232 }
233 }
234 else if ([object isEqual:self.downloadProgress]) {
235 if (self.downloadProgressBlock) {
236 self.downloadProgressBlock(object);
237 }
238 }
239 else if ([object isEqual:self.uploadProgress]) {
240 if (self.uploadProgressBlock) {
241 self.uploadProgressBlock(object);
242 }
243 }
244 }
245
246 #pragma mark - NSURLSessionTaskDelegate
247
248 - (void)URLSession:(__unused NSURLSession *)session
249 task:(NSURLSessionTask *)task
250 didCompleteWithError:(NSError *)error
251 {
252 __strong AFURLSessionManager *manager = self.manager;
253
254 __block id responseObject = nil;
255
256 __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
257 userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
258
259 //Performance Improvement from #2672
260 NSData *data = nil;
261 if (self.mutableData) {
262 data = [self.mutableData copy];
263 //We no longer need the reference, so nil it out to gain back some memory.
264 self.mutableData = nil;
265 }
266
267 if (self.downloadFileURL) {
268 userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
269 } else if (data) {
270 userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
271 }
272
273 if (error) {
274 userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
275
276 dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
277 if (self.completionHandler) {
278 self.completionHandler(task.response, responseObject, error);
279 }
280
281 dispatch_async(dispatch_get_main_queue(), ^{
282 [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
283 });
284 });
285 } else {
286 dispatch_async(url_session_manager_processing_queue(), ^{
287 NSError *serializationError = nil;
288 responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
289
290 if (self.downloadFileURL) {
291 responseObject = self.downloadFileURL;
292 }
293
294 if (responseObject) {
295 userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
296 }
297
298 if (serializationError) {
299 userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
300 }
301
302 dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
303 if (self.completionHandler) {
304 self.completionHandler(task.response, responseObject, serializationError);
305 }
306
307 dispatch_async(dispatch_get_main_queue(), ^{
308 [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
309 });
310 });
311 });
312 }
313 }
314
315 #pragma mark - NSURLSessionDataTaskDelegate
316
317 - (void)URLSession:(__unused NSURLSession *)session
318 dataTask:(__unused NSURLSessionDataTask *)dataTask
319 didReceiveData:(NSData *)data
320 {
321 [self.mutableData appendData:data];
322 }
323
324 #pragma mark - NSURLSessionDownloadTaskDelegate
325
326 - (void)URLSession:(NSURLSession *)session
327 downloadTask:(NSURLSessionDownloadTask *)downloadTask
328 didFinishDownloadingToURL:(NSURL *)location
329 {
330 NSError *fileManagerError = nil;
331 self.downloadFileURL = nil;
332
333 if (self.downloadTaskDidFinishDownloading) {
334 self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
335 if (self.downloadFileURL) {
336 [[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError];
337
338 if (fileManagerError) {
339 [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo];
340 }
341 }
342 }
343 }
344
345 @end
346
347 #pragma mark -
348
349 /**
350 * A workaround for issues related to key-value observing the `state` of an `NSURLSessionTask`.
351 *
352 * See:
353 * - https://github.com/AFNetworking/AFNetworking/issues/1477
354 * - https://github.com/AFNetworking/AFNetworking/issues/2638
355 * - https://github.com/AFNetworking/AFNetworking/pull/2702
356 */
357
358 static inline void af_swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) {
359 Method originalMethod = class_getInstanceMethod(theClass, originalSelector);
360 Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector);
361 method_exchangeImplementations(originalMethod, swizzledMethod);
362 }
363
364 static inline BOOL af_addMethod(Class theClass, SEL selector, Method method) {
365 return class_addMethod(theClass, selector, method_getImplementation(method), method_getTypeEncoding(method));
366 }
367
368 static NSString * const AFNSURLSessionTaskDidResumeNotification = @"com.alamofire.networking.nsurlsessiontask.resume";
369 static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofire.networking.nsurlsessiontask.suspend";
370
371 @interface _AFURLSessionTaskSwizzling : NSObject
372
373 @end
374
375 @implementation _AFURLSessionTaskSwizzling
376
377 + (void)load {
378 /**
379 WARNING: Trouble Ahead
380 https://github.com/AFNetworking/AFNetworking/pull/2702
381 */
382
383 if (NSClassFromString(@"NSURLSessionTask")) {
384 /**
385 iOS 7 and iOS 8 differ in NSURLSessionTask implementation, which makes the next bit of code a bit tricky.
386 Many Unit Tests have been built to validate as much of this behavior has possible.
387 Here is what we know:
388 - NSURLSessionTasks are implemented with class clusters, meaning the class you request from the API isn't actually the type of class you will get back.
389 - Simply referencing `[NSURLSessionTask class]` will not work. You need to ask an `NSURLSession` to actually create an object, and grab the class from there.
390 - On iOS 7, `localDataTask` is a `__NSCFLocalDataTask`, which inherits from `__NSCFLocalSessionTask`, which inherits from `__NSCFURLSessionTask`.
391 - On iOS 8, `localDataTask` is a `__NSCFLocalDataTask`, which inherits from `__NSCFLocalSessionTask`, which inherits from `NSURLSessionTask`.
392 - On iOS 7, `__NSCFLocalSessionTask` and `__NSCFURLSessionTask` are the only two classes that have their own implementations of `resume` and `suspend`, and `__NSCFLocalSessionTask` DOES NOT CALL SUPER. This means both classes need to be swizzled.
393 - On iOS 8, `NSURLSessionTask` is the only class that implements `resume` and `suspend`. This means this is the only class that needs to be swizzled.
394 - Because `NSURLSessionTask` is not involved in the class hierarchy for every version of iOS, its easier to add the swizzled methods to a dummy class and manage them there.
395
396 Some Assumptions:
397 - No implementations of `resume` or `suspend` call super. If this were to change in a future version of iOS, we'd need to handle it.
398 - No background task classes override `resume` or `suspend`
399
400 The current solution:
401 1) Grab an instance of `__NSCFLocalDataTask` by asking an instance of `NSURLSession` for a data task.
402 2) Grab a pointer to the original implementation of `af_resume`
403 3) Check to see if the current class has an implementation of resume. If so, continue to step 4.
404 4) Grab the super class of the current class.
405 5) Grab a pointer for the current class to the current implementation of `resume`.
406 6) Grab a pointer for the super class to the current implementation of `resume`.
407 7) If the current class implementation of `resume` is not equal to the super class implementation of `resume` AND the current implementation of `resume` is not equal to the original implementation of `af_resume`, THEN swizzle the methods
408 8) Set the current class to the super class, and repeat steps 3-8
409 */
410 NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
411 NSURLSession * session = [NSURLSession sessionWithConfiguration:configuration];
412 #pragma GCC diagnostic push
413 #pragma GCC diagnostic ignored "-Wnonnull"
414 NSURLSessionDataTask *localDataTask = [session dataTaskWithURL:nil];
415 #pragma clang diagnostic pop
416 IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([self class], @selector(af_resume)));
417 Class currentClass = [localDataTask class];
418
419 while (class_getInstanceMethod(currentClass, @selector(resume))) {
420 Class superClass = [currentClass superclass];
421 IMP classResumeIMP = method_getImplementation(class_getInstanceMethod(currentClass, @selector(resume)));
422 IMP superclassResumeIMP = method_getImplementation(class_getInstanceMethod(superClass, @selector(resume)));
423 if (classResumeIMP != superclassResumeIMP &&
424 originalAFResumeIMP != classResumeIMP) {
425 [self swizzleResumeAndSuspendMethodForClass:currentClass];
426 }
427 currentClass = [currentClass superclass];
428 }
429
430 [localDataTask cancel];
431 [session finishTasksAndInvalidate];
432 }
433 }
434
435 + (void)swizzleResumeAndSuspendMethodForClass:(Class)theClass {
436 Method afResumeMethod = class_getInstanceMethod(self, @selector(af_resume));
437 Method afSuspendMethod = class_getInstanceMethod(self, @selector(af_suspend));
438
439 if (af_addMethod(theClass, @selector(af_resume), afResumeMethod)) {
440 af_swizzleSelector(theClass, @selector(resume), @selector(af_resume));
441 }
442
443 if (af_addMethod(theClass, @selector(af_suspend), afSuspendMethod)) {
444 af_swizzleSelector(theClass, @selector(suspend), @selector(af_suspend));
445 }
446 }
447
448 - (NSURLSessionTaskState)state {
449 NSAssert(NO, @"State method should never be called in the actual dummy class");
450 return NSURLSessionTaskStateCanceling;
451 }
452
453 - (void)af_resume {
454 NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
455 NSURLSessionTaskState state = [self state];
456 [self af_resume];
457
458 if (state != NSURLSessionTaskStateRunning) {
459 [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self];
460 }
461 }
462
463 - (void)af_suspend {
464 NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
465 NSURLSessionTaskState state = [self state];
466 [self af_suspend];
467
468 if (state != NSURLSessionTaskStateSuspended) {
469 [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self];
470 }
471 }
472 @end
473
474 #pragma mark -
475
476 @interface AFURLSessionManager ()
477 @property (readwrite, nonatomic, strong) NSURLSessionConfiguration *sessionConfiguration;
478 @property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue;
479 @property (readwrite, nonatomic, strong) NSURLSession *session;
480 @property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;
481 @property (readonly, nonatomic, copy) NSString *taskDescriptionForSessionTasks;
482 @property (readwrite, nonatomic, strong) NSLock *lock;
483 @property (readwrite, nonatomic, copy) AFURLSessionDidBecomeInvalidBlock sessionDidBecomeInvalid;
484 @property (readwrite, nonatomic, copy) AFURLSessionDidReceiveAuthenticationChallengeBlock sessionDidReceiveAuthenticationChallenge;
485 @property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession;
486 @property (readwrite, nonatomic, copy) AFURLSessionTaskWillPerformHTTPRedirectionBlock taskWillPerformHTTPRedirection;
487 @property (readwrite, nonatomic, copy) AFURLSessionTaskDidReceiveAuthenticationChallengeBlock taskDidReceiveAuthenticationChallenge;
488 @property (readwrite, nonatomic, copy) AFURLSessionTaskNeedNewBodyStreamBlock taskNeedNewBodyStream;
489 @property (readwrite, nonatomic, copy) AFURLSessionTaskDidSendBodyDataBlock taskDidSendBodyData;
490 @property (readwrite, nonatomic, copy) AFURLSessionTaskDidCompleteBlock taskDidComplete;
491 @property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveResponseBlock dataTaskDidReceiveResponse;
492 @property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidBecomeDownloadTaskBlock dataTaskDidBecomeDownloadTask;
493 @property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveDataBlock dataTaskDidReceiveData;
494 @property (readwrite, nonatomic, copy) AFURLSessionDataTaskWillCacheResponseBlock dataTaskWillCacheResponse;
495 @property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
496 @property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidWriteDataBlock downloadTaskDidWriteData;
497 @property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidResumeBlock downloadTaskDidResume;
498 @end
499
500 @implementation AFURLSessionManager
501
502 - (instancetype)init {
503 return [self initWithSessionConfiguration:nil];
504 }
505
506 - (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
507 self = [super init];
508 if (!self) {
509 return nil;
510 }
511
512 if (!configuration) {
513 configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
514 }
515
516 self.sessionConfiguration = configuration;
517
518 self.operationQueue = [[NSOperationQueue alloc] init];
519 self.operationQueue.maxConcurrentOperationCount = 1;
520
521 self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
522
523 self.responseSerializer = [AFJSONResponseSerializer serializer];
524
525 self.securityPolicy = [AFSecurityPolicy defaultPolicy];
526
527 #if !TARGET_OS_WATCH
528 self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
529 #endif
530
531 self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
532
533 self.lock = [[NSLock alloc] init];
534 self.lock.name = AFURLSessionManagerLockName;
535
536 [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
537 for (NSURLSessionDataTask *task in dataTasks) {
538 [self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
539 }
540
541 for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
542 [self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
543 }
544
545 for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
546 [self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
547 }
548 }];
549
550 return self;
551 }
552
553 - (void)dealloc {
554 [[NSNotificationCenter defaultCenter] removeObserver:self];
555 }
556
557 #pragma mark -
558
559 - (NSString *)taskDescriptionForSessionTasks {
560 return [NSString stringWithFormat:@"%p", self];
561 }
562
563 - (void)taskDidResume:(NSNotification *)notification {
564 NSURLSessionTask *task = notification.object;
565 if ([task respondsToSelector:@selector(taskDescription)]) {
566 if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
567 dispatch_async(dispatch_get_main_queue(), ^{
568 [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task];
569 });
570 }
571 }
572 }
573
574 - (void)taskDidSuspend:(NSNotification *)notification {
575 NSURLSessionTask *task = notification.object;
576 if ([task respondsToSelector:@selector(taskDescription)]) {
577 if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
578 dispatch_async(dispatch_get_main_queue(), ^{
579 [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidSuspendNotification object:task];
580 });
581 }
582 }
583 }
584
585 #pragma mark -
586
587 - (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
588 NSParameterAssert(task);
589
590 AFURLSessionManagerTaskDelegate *delegate = nil;
591 [self.lock lock];
592 delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
593 [self.lock unlock];
594
595 return delegate;
596 }
597
598 - (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
599 forTask:(NSURLSessionTask *)task
600 {
601 NSParameterAssert(task);
602 NSParameterAssert(delegate);
603
604 [self.lock lock];
605 self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
606 [delegate setupProgressForTask:task];
607 [self addNotificationObserverForTask:task];
608 [self.lock unlock];
609 }
610
611 - (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
612 uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
613 downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
614 completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
615 {
616 AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
617 delegate.manager = self;
618 delegate.completionHandler = completionHandler;
619
620 dataTask.taskDescription = self.taskDescriptionForSessionTasks;
621 [self setDelegate:delegate forTask:dataTask];
622
623 delegate.uploadProgressBlock = uploadProgressBlock;
624 delegate.downloadProgressBlock = downloadProgressBlock;
625 }
626
627 - (void)addDelegateForUploadTask:(NSURLSessionUploadTask *)uploadTask
628 progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
629 completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
630 {
631 AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
632 delegate.manager = self;
633 delegate.completionHandler = completionHandler;
634
635 uploadTask.taskDescription = self.taskDescriptionForSessionTasks;
636
637 [self setDelegate:delegate forTask:uploadTask];
638
639 delegate.uploadProgressBlock = uploadProgressBlock;
640 }
641
642 - (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask
643 progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
644 destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
645 completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
646 {
647 AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
648 delegate.manager = self;
649 delegate.completionHandler = completionHandler;
650
651 if (destination) {
652 delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) {
653 return destination(location, task.response);
654 };
655 }
656
657 downloadTask.taskDescription = self.taskDescriptionForSessionTasks;
658
659 [self setDelegate:delegate forTask:downloadTask];
660
661 delegate.downloadProgressBlock = downloadProgressBlock;
662 }
663
664 - (void)removeDelegateForTask:(NSURLSessionTask *)task {
665 NSParameterAssert(task);
666
667 AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
668 [self.lock lock];
669 [delegate cleanUpProgressForTask:task];
670 [self removeNotificationObserverForTask:task];
671 [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
672 [self.lock unlock];
673 }
674
675 #pragma mark -
676
677 - (NSArray *)tasksForKeyPath:(NSString *)keyPath {
678 __block NSArray *tasks = nil;
679 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
680 [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
681 if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) {
682 tasks = dataTasks;
683 } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) {
684 tasks = uploadTasks;
685 } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) {
686 tasks = downloadTasks;
687 } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) {
688 tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"];
689 }
690
691 dispatch_semaphore_signal(semaphore);
692 }];
693
694 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
695
696 return tasks;
697 }
698
699 - (NSArray *)tasks {
700 return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
701 }
702
703 - (NSArray *)dataTasks {
704 return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
705 }
706
707 - (NSArray *)uploadTasks {
708 return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
709 }
710
711 - (NSArray *)downloadTasks {
712 return [self tasksForKeyPath:NSStringFromSelector(_cmd)];
713 }
714
715 #pragma mark -
716
717 - (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks {
718 dispatch_async(dispatch_get_main_queue(), ^{
719 if (cancelPendingTasks) {
720 [self.session invalidateAndCancel];
721 } else {
722 [self.session finishTasksAndInvalidate];
723 }
724 });
725 }
726
727 #pragma mark -
728
729 - (void)setResponseSerializer:(id <AFURLResponseSerialization>)responseSerializer {
730 NSParameterAssert(responseSerializer);
731
732 _responseSerializer = responseSerializer;
733 }
734
735 #pragma mark -
736 - (void)addNotificationObserverForTask:(NSURLSessionTask *)task {
737 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:task];
738 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:task];
739 }
740
741 - (void)removeNotificationObserverForTask:(NSURLSessionTask *)task {
742 [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidSuspendNotification object:task];
743 [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidResumeNotification object:task];
744 }
745
746 #pragma mark -
747
748 - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
749 completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
750 {
751 return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler];
752 }
753
754 - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
755 uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
756 downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
757 completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {
758
759 __block NSURLSessionDataTask *dataTask = nil;
760 url_session_manager_create_task_safely(^{
761 dataTask = [self.session dataTaskWithRequest:request];
762 });
763
764 [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
765
766 return dataTask;
767 }
768
769 #pragma mark -
770
771 - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
772 fromFile:(NSURL *)fileURL
773 progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
774 completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
775 {
776 __block NSURLSessionUploadTask *uploadTask = nil;
777 url_session_manager_create_task_safely(^{
778 uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
779 });
780
781 // uploadTask may be nil on iOS7 because uploadTaskWithRequest:fromFile: may return nil despite being documented as nonnull (https://devforums.apple.com/message/926113#926113)
782 if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) {
783 for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) {
784 uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
785 }
786 }
787
788 [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
789
790 return uploadTask;
791 }
792
793 - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
794 fromData:(NSData *)bodyData
795 progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
796 completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
797 {
798 __block NSURLSessionUploadTask *uploadTask = nil;
799 url_session_manager_create_task_safely(^{
800 uploadTask = [self.session uploadTaskWithRequest:request fromData:bodyData];
801 });
802
803 [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
804
805 return uploadTask;
806 }
807
808 - (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
809 progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
810 completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
811 {
812 __block NSURLSessionUploadTask *uploadTask = nil;
813 url_session_manager_create_task_safely(^{
814 uploadTask = [self.session uploadTaskWithStreamedRequest:request];
815 });
816
817 [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
818
819 return uploadTask;
820 }
821
822 #pragma mark -
823
824 - (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
825 progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
826 destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
827 completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
828 {
829 __block NSURLSessionDownloadTask *downloadTask = nil;
830 url_session_manager_create_task_safely(^{
831 downloadTask = [self.session downloadTaskWithRequest:request];
832 });
833
834 [self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
835
836 return downloadTask;
837 }
838
839 - (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
840 progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
841 destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
842 completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
843 {
844 __block NSURLSessionDownloadTask *downloadTask = nil;
845 url_session_manager_create_task_safely(^{
846 downloadTask = [self.session downloadTaskWithResumeData:resumeData];
847 });
848
849 [self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
850
851 return downloadTask;
852 }
853
854 #pragma mark -
855 - (NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task {
856 return [[self delegateForTask:task] uploadProgress];
857 }
858
859 - (NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task {
860 return [[self delegateForTask:task] downloadProgress];
861 }
862
863 #pragma mark -
864
865 - (void)setSessionDidBecomeInvalidBlock:(void (^)(NSURLSession *session, NSError *error))block {
866 self.sessionDidBecomeInvalid = block;
867 }
868
869 - (void)setSessionDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block {
870 self.sessionDidReceiveAuthenticationChallenge = block;
871 }
872
873 - (void)setDidFinishEventsForBackgroundURLSessionBlock:(void (^)(NSURLSession *session))block {
874 self.didFinishEventsForBackgroundURLSession = block;
875 }
876
877 #pragma mark -
878
879 - (void)setTaskNeedNewBodyStreamBlock:(NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block {
880 self.taskNeedNewBodyStream = block;
881 }
882
883 - (void)setTaskWillPerformHTTPRedirectionBlock:(NSURLRequest * (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block {
884 self.taskWillPerformHTTPRedirection = block;
885 }
886
887 - (void)setTaskDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block {
888 self.taskDidReceiveAuthenticationChallenge = block;
889 }
890
891 - (void)setTaskDidSendBodyDataBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block {
892 self.taskDidSendBodyData = block;
893 }
894
895 - (void)setTaskDidCompleteBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, NSError *error))block {
896 self.taskDidComplete = block;
897 }
898
899 #pragma mark -
900
901 - (void)setDataTaskDidReceiveResponseBlock:(NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block {
902 self.dataTaskDidReceiveResponse = block;
903 }
904
905 - (void)setDataTaskDidBecomeDownloadTaskBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block {
906 self.dataTaskDidBecomeDownloadTask = block;
907 }
908
909 - (void)setDataTaskDidReceiveDataBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block {
910 self.dataTaskDidReceiveData = block;
911 }
912
913 - (void)setDataTaskWillCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block {
914 self.dataTaskWillCacheResponse = block;
915 }
916
917 #pragma mark -
918
919 - (void)setDownloadTaskDidFinishDownloadingBlock:(NSURL * (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block {
920 self.downloadTaskDidFinishDownloading = block;
921 }
922
923 - (void)setDownloadTaskDidWriteDataBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block {
924 self.downloadTaskDidWriteData = block;
925 }
926
927 - (void)setDownloadTaskDidResumeBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block {
928 self.downloadTaskDidResume = block;
929 }
930
931 #pragma mark - NSObject
932
933 - (NSString *)description {
934 return [NSString stringWithFormat:@"<%@: %p, session: %@, operationQueue: %@>", NSStringFromClass([self class]), self, self.session, self.operationQueue];
935 }
936
937 - (BOOL)respondsToSelector:(SEL)selector {
938 if (selector == @selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)) {
939 return self.taskWillPerformHTTPRedirection != nil;
940 } else if (selector == @selector(URLSession:dataTask:didReceiveResponse:completionHandler:)) {
941 return self.dataTaskDidReceiveResponse != nil;
942 } else if (selector == @selector(URLSession:dataTask:willCacheResponse:completionHandler:)) {
943 return self.dataTaskWillCacheResponse != nil;
944 } else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) {
945 return self.didFinishEventsForBackgroundURLSession != nil;
946 }
947
948 return [[self class] instancesRespondToSelector:selector];
949 }
950
951 #pragma mark - NSURLSessionDelegate
952
953 - (void)URLSession:(NSURLSession *)session
954 didBecomeInvalidWithError:(NSError *)error
955 {
956 if (self.sessionDidBecomeInvalid) {
957 self.sessionDidBecomeInvalid(session, error);
958 }
959
960 [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session];
961 }
962
963 - (void)URLSession:(NSURLSession *)session
964 didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
965 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
966 {
967 NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
968 __block NSURLCredential *credential = nil;
969
970 if (self.sessionDidReceiveAuthenticationChallenge) {
971 disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential);
972 } else {
973 if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
974 if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
975 credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
976 if (credential) {
977 disposition = NSURLSessionAuthChallengeUseCredential;
978 } else {
979 disposition = NSURLSessionAuthChallengePerformDefaultHandling;
980 }
981 } else {
982 disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
983 }
984 } else {
985 disposition = NSURLSessionAuthChallengePerformDefaultHandling;
986 }
987 }
988
989 if (completionHandler) {
990 completionHandler(disposition, credential);
991 }
992 }
993
994 #pragma mark - NSURLSessionTaskDelegate
995
996 - (void)URLSession:(NSURLSession *)session
997 task:(NSURLSessionTask *)task
998 willPerformHTTPRedirection:(NSHTTPURLResponse *)response
999 newRequest:(NSURLRequest *)request
1000 completionHandler:(void (^)(NSURLRequest *))completionHandler
1001 {
1002 NSURLRequest *redirectRequest = request;
1003
1004 if (self.taskWillPerformHTTPRedirection) {
1005 redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request);
1006 }
1007
1008 if (completionHandler) {
1009 completionHandler(redirectRequest);
1010 }
1011 }
1012
1013 - (void)URLSession:(NSURLSession *)session
1014 task:(NSURLSessionTask *)task
1015 didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
1016 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
1017 {
1018 NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
1019 __block NSURLCredential *credential = nil;
1020
1021 if (self.taskDidReceiveAuthenticationChallenge) {
1022 disposition = self.taskDidReceiveAuthenticationChallenge(session, task, challenge, &credential);
1023 } else {
1024 if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
1025 if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
1026 disposition = NSURLSessionAuthChallengeUseCredential;
1027 credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
1028 } else {
1029 disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
1030 }
1031 } else {
1032 disposition = NSURLSessionAuthChallengePerformDefaultHandling;
1033 }
1034 }
1035
1036 if (completionHandler) {
1037 completionHandler(disposition, credential);
1038 }
1039 }
1040
1041 - (void)URLSession:(NSURLSession *)session
1042 task:(NSURLSessionTask *)task
1043 needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler
1044 {
1045 NSInputStream *inputStream = nil;
1046
1047 if (self.taskNeedNewBodyStream) {
1048 inputStream = self.taskNeedNewBodyStream(session, task);
1049 } else if (task.originalRequest.HTTPBodyStream && [task.originalRequest.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) {
1050 inputStream = [task.originalRequest.HTTPBodyStream copy];
1051 }
1052
1053 if (completionHandler) {
1054 completionHandler(inputStream);
1055 }
1056 }
1057
1058 - (void)URLSession:(NSURLSession *)session
1059 task:(NSURLSessionTask *)task
1060 didSendBodyData:(int64_t)bytesSent
1061 totalBytesSent:(int64_t)totalBytesSent
1062 totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
1063 {
1064
1065 int64_t totalUnitCount = totalBytesExpectedToSend;
1066 if(totalUnitCount == NSURLSessionTransferSizeUnknown) {
1067 NSString *contentLength = [task.originalRequest valueForHTTPHeaderField:@"Content-Length"];
1068 if(contentLength) {
1069 totalUnitCount = (int64_t) [contentLength longLongValue];
1070 }
1071 }
1072
1073 if (self.taskDidSendBodyData) {
1074 self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount);
1075 }
1076 }
1077
1078 - (void)URLSession:(NSURLSession *)session
1079 task:(NSURLSessionTask *)task
1080 didCompleteWithError:(NSError *)error
1081 {
1082 AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
1083
1084 // delegate may be nil when completing a task in the background
1085 if (delegate) {
1086 [delegate URLSession:session task:task didCompleteWithError:error];
1087
1088 [self removeDelegateForTask:task];
1089 }
1090
1091 if (self.taskDidComplete) {
1092 self.taskDidComplete(session, task, error);
1093 }
1094 }
1095
1096 #pragma mark - NSURLSessionDataDelegate
1097
1098 - (void)URLSession:(NSURLSession *)session
1099 dataTask:(NSURLSessionDataTask *)dataTask
1100 didReceiveResponse:(NSURLResponse *)response
1101 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
1102 {
1103 NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
1104
1105 if (self.dataTaskDidReceiveResponse) {
1106 disposition = self.dataTaskDidReceiveResponse(session, dataTask, response);
1107 }
1108
1109 if (completionHandler) {
1110 completionHandler(disposition);
1111 }
1112 }
1113
1114 - (void)URLSession:(NSURLSession *)session
1115 dataTask:(NSURLSessionDataTask *)dataTask
1116 didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
1117 {
1118 AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
1119 if (delegate) {
1120 [self removeDelegateForTask:dataTask];
1121 [self setDelegate:delegate forTask:downloadTask];
1122 }
1123
1124 if (self.dataTaskDidBecomeDownloadTask) {
1125 self.dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask);
1126 }
1127 }
1128
1129 - (void)URLSession:(NSURLSession *)session
1130 dataTask:(NSURLSessionDataTask *)dataTask
1131 didReceiveData:(NSData *)data
1132 {
1133
1134 AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
1135 [delegate URLSession:session dataTask:dataTask didReceiveData:data];
1136
1137 if (self.dataTaskDidReceiveData) {
1138 self.dataTaskDidReceiveData(session, dataTask, data);
1139 }
1140 }
1141
1142 - (void)URLSession:(NSURLSession *)session
1143 dataTask:(NSURLSessionDataTask *)dataTask
1144 willCacheResponse:(NSCachedURLResponse *)proposedResponse
1145 completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler
1146 {
1147 NSCachedURLResponse *cachedResponse = proposedResponse;
1148
1149 if (self.dataTaskWillCacheResponse) {
1150 cachedResponse = self.dataTaskWillCacheResponse(session, dataTask, proposedResponse);
1151 }
1152
1153 if (completionHandler) {
1154 completionHandler(cachedResponse);
1155 }
1156 }
1157
1158 - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
1159 if (self.didFinishEventsForBackgroundURLSession) {
1160 dispatch_async(dispatch_get_main_queue(), ^{
1161 self.didFinishEventsForBackgroundURLSession(session);
1162 });
1163 }
1164 }
1165
1166 #pragma mark - NSURLSessionDownloadDelegate
1167
1168 - (void)URLSession:(NSURLSession *)session
1169 downloadTask:(NSURLSessionDownloadTask *)downloadTask
1170 didFinishDownloadingToURL:(NSURL *)location
1171 {
1172 AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
1173 if (self.downloadTaskDidFinishDownloading) {
1174 NSURL *fileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
1175 if (fileURL) {
1176 delegate.downloadFileURL = fileURL;
1177 NSError *error = nil;
1178 [[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error];
1179 if (error) {
1180 [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:error.userInfo];
1181 }
1182
1183 return;
1184 }
1185 }
1186
1187 if (delegate) {
1188 [delegate URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location];
1189 }
1190 }
1191
1192 - (void)URLSession:(NSURLSession *)session
1193 downloadTask:(NSURLSessionDownloadTask *)downloadTask
1194 didWriteData:(int64_t)bytesWritten
1195 totalBytesWritten:(int64_t)totalBytesWritten
1196 totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
1197 {
1198 if (self.downloadTaskDidWriteData) {
1199 self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
1200 }
1201 }
1202
1203 - (void)URLSession:(NSURLSession *)session
1204 downloadTask:(NSURLSessionDownloadTask *)downloadTask
1205 didResumeAtOffset:(int64_t)fileOffset
1206 expectedTotalBytes:(int64_t)expectedTotalBytes
1207 {
1208 if (self.downloadTaskDidResume) {
1209 self.downloadTaskDidResume(session, downloadTask, fileOffset, expectedTotalBytes);
1210 }
1211 }
1212
1213 #pragma mark - NSSecureCoding
1214
1215 + (BOOL)supportsSecureCoding {
1216 return YES;
1217 }
1218
1219 - (instancetype)initWithCoder:(NSCoder *)decoder {
1220 NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"];
1221
1222 self = [self initWithSessionConfiguration:configuration];
1223 if (!self) {
1224 return nil;
1225 }
1226
1227 return self;
1228 }
1229
1230 - (void)encodeWithCoder:(NSCoder *)coder {
1231 [coder encodeObject:self.session.configuration forKey:@"sessionConfiguration"];
1232 }
1233
1234 #pragma mark - NSCopying
1235
1236 - (instancetype)copyWithZone:(NSZone *)zone {
1237 return [[[self class] allocWithZone:zone] initWithSessionConfiguration:self.session.configuration];
1238 }
1239
1240 @end
1
2 /*
3
4 Copyright (c) 2013-2014 RedBearLab
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7
8 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11
12 */
13
14 #import <Foundation/Foundation.h>
15 #if TARGET_OS_IPHONE
16 #import <CoreBluetooth/CoreBluetooth.h>
17 #else
18 #import <IOBluetooth/IOBluetooth.h>
19 #endif
20
21 @protocol BLEDelegate
22 @optional
23 -(void) bleDidConnect;
24 -(void) bleDidDisconnect;
25 -(void) bleDidUpdateRSSI:(NSNumber *) rssi;
26 -(void) bleDidReceiveData:(unsigned char *) data length:(int) length;
27 @required
28 @end
29
30 @interface BLE : NSObject <CBCentralManagerDelegate, CBPeripheralDelegate> {
31
32 }
33
34 @property (nonatomic,assign) id <BLEDelegate> delegate;
35 @property (strong, nonatomic) NSMutableArray *peripherals;
36 @property (strong, nonatomic) NSMutableArray *peripheralsRssi;
37 @property (strong, nonatomic) CBCentralManager *CM;
38 @property (strong, nonatomic) CBPeripheral *activePeripheral;
39
40 -(void) enableReadNotification:(CBPeripheral *)p;
41 -(void) read;
42 -(void) writeValue:(CBUUID *)serviceUUID characteristicUUID:(CBUUID *)characteristicUUID p:(CBPeripheral *)p data:(NSData *)data;
43
44 -(BOOL) isConnected;
45 -(void) write:(NSData *)d;
46 -(void) readRSSI;
47
48 -(void) controlSetup;
49 -(int) findBLEPeripherals:(int) timeout;
50 -(void) connectPeripheral:(CBPeripheral *)peripheral;
51
52 -(UInt16) swap:(UInt16) s;
53 -(const char *) centralManagerStateToString:(int)state;
54 -(void) scanTimer:(NSTimer *)timer;
55 -(void) printKnownPeripherals;
56 -(void) printPeripheralInfo:(CBPeripheral*)peripheral;
57
58 -(void) getAllServicesFromPeripheral:(CBPeripheral *)p;
59 -(void) getAllCharacteristicsFromPeripheral:(CBPeripheral *)p;
60 -(CBService *) findServiceFromUUID:(CBUUID *)UUID p:(CBPeripheral *)p;
61 -(CBCharacteristic *) findCharacteristicFromUUID:(CBUUID *)UUID service:(CBService*)service;
62
63 //-(NSString *) NSUUIDToString:(NSUUID *) UUID;
64 -(NSString *) CBUUIDToString:(CBUUID *) UUID;
65
66 -(int) compareCBUUID:(CBUUID *) UUID1 UUID2:(CBUUID *)UUID2;
67 -(int) compareCBUUIDToInt:(CBUUID *) UUID1 UUID2:(UInt16)UUID2;
68 -(UInt16) CBUUIDToInt:(CBUUID *) UUID;
69 -(BOOL) UUIDSAreEqual:(NSUUID *)UUID1 UUID2:(NSUUID *)UUID2;
70
71 @end
1
2 /*
3
4 Copyright (c) 2013-2014 RedBearLab
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7
8 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11
12 */
13
14 #import "BLE.h"
15 #import "BLEDefines.h"
16
17 @implementation BLE
18
19 @synthesize delegate;
20 @synthesize CM;
21 @synthesize peripherals;
22 @synthesize peripheralsRssi;
23 @synthesize activePeripheral;
24
25 static bool isConnected = false;
26 static int rssi = 0;
27
28 -(void) readRSSI
29 {
30 [activePeripheral readRSSI];
31 }
32
33 -(BOOL) isConnected
34 {
35 return isConnected;
36 }
37
38 -(void) read
39 {
40 CBUUID *uuid_service = [CBUUID UUIDWithString:@RBL_SERVICE_UUID];
41 CBUUID *uuid_char = [CBUUID UUIDWithString:@RBL_CHAR_TX_UUID];
42
43 [self readValue:uuid_service characteristicUUID:uuid_char p:activePeripheral];
44 }
45
46 -(void) write:(NSData *)d
47 {
48 CBUUID *uuid_service = [CBUUID UUIDWithString:@RBL_SERVICE_UUID];
49 CBUUID *uuid_char = [CBUUID UUIDWithString:@RBL_CHAR_RX_UUID];
50
51 [self writeValue:uuid_service characteristicUUID:uuid_char p:activePeripheral data:d];
52 }
53
54 -(void) enableReadNotification:(CBPeripheral *)p
55 {
56 CBUUID *uuid_service = [CBUUID UUIDWithString:@RBL_SERVICE_UUID];
57 CBUUID *uuid_char = [CBUUID UUIDWithString:@RBL_CHAR_TX_UUID];
58
59 [self notification:uuid_service characteristicUUID:uuid_char p:p on:YES];
60 }
61
62 -(void) notification:(CBUUID *)serviceUUID characteristicUUID:(CBUUID *)characteristicUUID p:(CBPeripheral *)p on:(BOOL)on
63 {
64 CBService *service = [self findServiceFromUUID:serviceUUID p:p];
65
66 if (!service)
67 {
68 NSLog(@"Could not find service with UUID %@ on peripheral with UUID %@",
69 [self CBUUIDToString:serviceUUID],
70 p.identifier.UUIDString);
71
72 return;
73 }
74
75 CBCharacteristic *characteristic = [self findCharacteristicFromUUID:characteristicUUID service:service];
76
77 if (!characteristic)
78 {
79 NSLog(@"Could not find characteristic with UUID %@ on service with UUID %@ on peripheral with UUID %@",
80 [self CBUUIDToString:characteristicUUID],
81 [self CBUUIDToString:serviceUUID],
82 p.identifier.UUIDString);
83
84 return;
85 }
86
87 [p setNotifyValue:on forCharacteristic:characteristic];
88 }
89
90 -(UInt16) frameworkVersion
91 {
92 return RBL_BLE_FRAMEWORK_VER;
93 }
94
95 -(NSString *) CBUUIDToString:(CBUUID *) cbuuid;
96 {
97 NSData *data = cbuuid.data;
98
99 if ([data length] == 2)
100 {
101 const unsigned char *tokenBytes = [data bytes];
102 return [NSString stringWithFormat:@"%02x%02x", tokenBytes[0], tokenBytes[1]];
103 }
104 else if ([data length] == 16)
105 {
106 NSUUID* nsuuid = [[NSUUID alloc] initWithUUIDBytes:[data bytes]];
107 return [nsuuid UUIDString];
108 }
109
110 return [cbuuid description];
111 }
112
113 -(void) readValue: (CBUUID *)serviceUUID characteristicUUID:(CBUUID *)characteristicUUID p:(CBPeripheral *)p
114 {
115 CBService *service = [self findServiceFromUUID:serviceUUID p:p];
116
117 if (!service)
118 {
119 NSLog(@"Could not find service with UUID %@ on peripheral with UUID %@",
120 [self CBUUIDToString:serviceUUID],
121 p.identifier.UUIDString);
122
123 return;
124 }
125
126 CBCharacteristic *characteristic = [self findCharacteristicFromUUID:characteristicUUID service:service];
127
128 if (!characteristic)
129 {
130 NSLog(@"Could not find characteristic with UUID %@ on service with UUID %@ on peripheral with UUID %@",
131 [self CBUUIDToString:characteristicUUID],
132 [self CBUUIDToString:serviceUUID],
133 p.identifier.UUIDString);
134
135 return;
136 }
137
138 [p readValueForCharacteristic:characteristic];
139 }
140
141 -(void) writeValue:(CBUUID *)serviceUUID characteristicUUID:(CBUUID *)characteristicUUID p:(CBPeripheral *)p data:(NSData *)data
142 {
143 CBService *service = [self findServiceFromUUID:serviceUUID p:p];
144
145 if (!service)
146 {
147 NSLog(@"Could not find service with UUID %@ on peripheral with UUID %@",
148 [self CBUUIDToString:serviceUUID],
149 p.identifier.UUIDString);
150
151 return;
152 }
153
154 CBCharacteristic *characteristic = [self findCharacteristicFromUUID:characteristicUUID service:service];
155
156 if (!characteristic)
157 {
158 NSLog(@"Could not find characteristic with UUID %@ on service with UUID %@ on peripheral with UUID %@",
159 [self CBUUIDToString:characteristicUUID],
160 [self CBUUIDToString:serviceUUID],
161 p.identifier.UUIDString);
162
163 return;
164 }
165
166 [p writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
167 }
168
169 -(UInt16) swap:(UInt16)s
170 {
171 UInt16 temp = s << 8;
172 temp |= (s >> 8);
173 return temp;
174 }
175
176 - (void) controlSetup
177 {
178 self.CM = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
179 }
180
181 - (int) findBLEPeripherals:(int) timeout
182 {
183 NSLog(@"start finding");
184
185 if (self.CM.state != CBCentralManagerStatePoweredOn)
186 {
187 NSLog(@"CoreBluetooth not correctly initialized !");
188 NSLog(@"State = %d (%s)\r\n", self.CM.state, [self centralManagerStateToString:self.CM.state]);
189 return -1;
190 }
191
192 [NSTimer scheduledTimerWithTimeInterval:(float)timeout target:self selector:@selector(scanTimer:) userInfo:nil repeats:NO];
193
194 #if TARGET_OS_IPHONE
195 [self.CM scanForPeripheralsWithServices:[NSArray arrayWithObject:[CBUUID UUIDWithString:@RBL_SERVICE_UUID]] options:nil];
196 #else
197 [self.CM scanForPeripheralsWithServices:nil options:nil]; // Start scanning
198 #endif
199
200 NSLog(@"scanForPeripheralsWithServices");
201
202 return 0; // Started scanning OK !
203 }
204
205 - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;
206 {
207 [[self delegate] bleDidDisconnect];
208
209 isConnected = false;
210 }
211
212 - (void) connectPeripheral:(CBPeripheral *)peripheral
213 {
214 NSLog(@"Connecting to peripheral with UUID : %@", peripheral.identifier.UUIDString);
215
216 self.activePeripheral = peripheral;
217 self.activePeripheral.delegate = self;
218 [self.CM connectPeripheral:self.activePeripheral
219 options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];
220 }
221
222 - (const char *) centralManagerStateToString: (int)state
223 {
224 switch(state)
225 {
226 case CBCentralManagerStateUnknown:
227 return "State unknown (CBCentralManagerStateUnknown)";
228 case CBCentralManagerStateResetting:
229 return "State resetting (CBCentralManagerStateUnknown)";
230 case CBCentralManagerStateUnsupported:
231 return "State BLE unsupported (CBCentralManagerStateResetting)";
232 case CBCentralManagerStateUnauthorized:
233 return "State unauthorized (CBCentralManagerStateUnauthorized)";
234 case CBCentralManagerStatePoweredOff:
235 return "State BLE powered off (CBCentralManagerStatePoweredOff)";
236 case CBCentralManagerStatePoweredOn:
237 return "State powered up and ready (CBCentralManagerStatePoweredOn)";
238 default:
239 return "State unknown";
240 }
241
242 return "Unknown state";
243 }
244
245 - (void) scanTimer:(NSTimer *)timer
246 {
247 [self.CM stopScan];
248 NSLog(@"Stopped Scanning");
249 NSLog(@"Known peripherals : %lu", (unsigned long)[self.peripherals count]);
250 [self printKnownPeripherals];
251 }
252
253 - (void) printKnownPeripherals
254 {
255 NSLog(@"List of currently known peripherals :");
256
257 for (int i = 0; i < self.peripherals.count; i++)
258 {
259 CBPeripheral *p = [self.peripherals objectAtIndex:i];
260
261 if (p.identifier != NULL)
262 NSLog(@"%d | %@", i, p.identifier.UUIDString);
263 else
264 NSLog(@"%d | NULL", i);
265
266 [self printPeripheralInfo:p];
267 }
268 }
269
270 - (void) printPeripheralInfo:(CBPeripheral*)peripheral
271 {
272 NSLog(@"------------------------------------");
273 NSLog(@"Peripheral Info :");
274
275 if (peripheral.identifier != NULL)
276 NSLog(@"UUID : %@", peripheral.identifier.UUIDString);
277 else
278 NSLog(@"UUID : NULL");
279
280 NSLog(@"Name : %@", peripheral.name);
281 NSLog(@"-------------------------------------");
282 }
283
284 - (BOOL) UUIDSAreEqual:(NSUUID *)UUID1 UUID2:(NSUUID *)UUID2
285 {
286 if ([UUID1.UUIDString isEqualToString:UUID2.UUIDString])
287 return TRUE;
288 else
289 return FALSE;
290 }
291
292 -(void) getAllServicesFromPeripheral:(CBPeripheral *)p
293 {
294 [p discoverServices:nil]; // Discover all services without filter
295 }
296
297 -(void) getAllCharacteristicsFromPeripheral:(CBPeripheral *)p
298 {
299 for (int i=0; i < p.services.count; i++)
300 {
301 CBService *s = [p.services objectAtIndex:i];
302 // printf("Fetching characteristics for service with UUID : %s\r\n",[self CBUUIDToString:s.UUID]);
303 [p discoverCharacteristics:nil forService:s];
304 }
305 }
306
307 -(int) compareCBUUID:(CBUUID *) UUID1 UUID2:(CBUUID *)UUID2
308 {
309 char b1[16];
310 char b2[16];
311 [UUID1.data getBytes:b1];
312 [UUID2.data getBytes:b2];
313
314 if (memcmp(b1, b2, UUID1.data.length) == 0)
315 return 1;
316 else
317 return 0;
318 }
319
320 -(int) compareCBUUIDToInt:(CBUUID *)UUID1 UUID2:(UInt16)UUID2
321 {
322 char b1[16];
323
324 [UUID1.data getBytes:b1];
325 UInt16 b2 = [self swap:UUID2];
326
327 if (memcmp(b1, (char *)&b2, 2) == 0)
328 return 1;
329 else
330 return 0;
331 }
332
333 -(UInt16) CBUUIDToInt:(CBUUID *) UUID
334 {
335 char b1[16];
336 [UUID.data getBytes:b1];
337 return ((b1[0] << 8) | b1[1]);
338 }
339
340 -(CBUUID *) IntToCBUUID:(UInt16)UUID
341 {
342 char t[16];
343 t[0] = ((UUID >> 8) & 0xff); t[1] = (UUID & 0xff);
344 NSData *data = [[NSData alloc] initWithBytes:t length:16];
345 return [CBUUID UUIDWithData:data];
346 }
347
348 -(CBService *) findServiceFromUUID:(CBUUID *)UUID p:(CBPeripheral *)p
349 {
350 for(int i = 0; i < p.services.count; i++)
351 {
352 CBService *s = [p.services objectAtIndex:i];
353 if ([self compareCBUUID:s.UUID UUID2:UUID])
354 return s;
355 }
356
357 return nil; //Service not found on this peripheral
358 }
359
360 -(CBCharacteristic *) findCharacteristicFromUUID:(CBUUID *)UUID service:(CBService*)service
361 {
362 for(int i=0; i < service.characteristics.count; i++)
363 {
364 CBCharacteristic *c = [service.characteristics objectAtIndex:i];
365 if ([self compareCBUUID:c.UUID UUID2:UUID]) return c;
366 }
367
368 return nil; //Characteristic not found on this service
369 }
370
371 #if TARGET_OS_IPHONE
372 //-- no need for iOS
373 #else
374 - (BOOL) isLECapableHardware
375 {
376 NSString * state = nil;
377
378 switch ([CM state])
379 {
380 case CBCentralManagerStateUnsupported:
381 state = @"The platform/hardware doesn't support Bluetooth Low Energy.";
382 break;
383
384 case CBCentralManagerStateUnauthorized:
385 state = @"The app is not authorized to use Bluetooth Low Energy.";
386 break;
387
388 case CBCentralManagerStatePoweredOff:
389 state = @"Bluetooth is currently powered off.";
390 break;
391
392 case CBCentralManagerStatePoweredOn:
393 return TRUE;
394
395 case CBCentralManagerStateUnknown:
396 default:
397 return FALSE;
398
399 }
400
401 NSLog(@"Central manager state: %@", state);
402
403 NSAlert *alert = [[NSAlert alloc] init];
404 [alert setMessageText:state];
405 [alert addButtonWithTitle:@"OK"];
406 [alert setIcon:[[NSImage alloc] initWithContentsOfFile:@"AppIcon"]];
407 [alert beginSheetModalForWindow:nil modalDelegate:self didEndSelector:nil contextInfo:nil];
408
409 return FALSE;
410 }
411 #endif
412
413 - (void)centralManagerDidUpdateState:(CBCentralManager *)central
414 {
415 #if TARGET_OS_IPHONE
416 NSLog(@"Status of CoreBluetooth central manager changed %d (%s)", central.state, [self centralManagerStateToString:central.state]);
417 #else
418 [self isLECapableHardware];
419 #endif
420 }
421
422 - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
423 {
424 if (!self.peripherals) {
425 self.peripherals = [[NSMutableArray alloc] initWithObjects:peripheral,nil];
426 self.peripheralsRssi = [[NSMutableArray alloc] initWithObjects:RSSI, nil];
427 }
428 else
429 {
430 for(int i = 0; i < self.peripherals.count; i++)
431 {
432 CBPeripheral *p = [self.peripherals objectAtIndex:i];
433
434 if ((p.identifier == NULL) || (peripheral.identifier == NULL))
435 continue;
436
437 if ([self UUIDSAreEqual:p.identifier UUID2:peripheral.identifier])
438 {
439 [self.peripherals replaceObjectAtIndex:i withObject:peripheral];
440 NSLog(@"Duplicate UUID found updating...");
441 return;
442 }
443 }
444
445 [self.peripherals addObject:peripheral];
446 [self.peripheralsRssi addObject:RSSI];
447
448 NSLog(@"New UUID, adding");
449 }
450
451 NSLog(@"didDiscoverPeripheral");
452 }
453
454 - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
455 {
456 if (peripheral.identifier != NULL)
457 NSLog(@"Connected to %@ successful", peripheral.identifier.UUIDString);
458 else
459 NSLog(@"Connected to NULL successful");
460
461 self.activePeripheral = peripheral;
462 [self.activePeripheral discoverServices:nil];
463 }
464
465 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
466 {
467 if (!error)
468 {
469 // printf("Characteristics of service with UUID : %s found\n",[self CBUUIDToString:service.UUID]);
470
471 for (int i=0; i < service.characteristics.count; i++)
472 {
473 // CBCharacteristic *c = [service.characteristics objectAtIndex:i];
474 // printf("Found characteristic %s\n",[ self CBUUIDToString:c.UUID]);
475 CBService *s = [peripheral.services objectAtIndex:(peripheral.services.count - 1)];
476
477 if ([service.UUID isEqual:s.UUID])
478 {
479 [self enableReadNotification:activePeripheral];
480 [[self delegate] bleDidConnect];
481 isConnected = true;
482
483 break;
484 }
485 }
486 }
487 else
488 {
489 NSLog(@"Characteristic discorvery unsuccessful!");
490 }
491 }
492
493 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
494 {
495 if (!error)
496 {
497 // printf("Services of peripheral with UUID : %s found\n",[self UUIDToString:peripheral.UUID]);
498 [self getAllCharacteristicsFromPeripheral:peripheral];
499 }
500 else
501 {
502 NSLog(@"Service discovery was unsuccessful!");
503 }
504 }
505
506 - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
507 {
508 if (!error)
509 {
510 // printf("Updated notification state for characteristic with UUID %s on service with UUID %s on peripheral with UUID %s\r\n",[self CBUUIDToString:characteristic.UUID],[self CBUUIDToString:characteristic.service.UUID],[self UUIDToString:peripheral.UUID]);
511 }
512 else
513 {
514 NSLog(@"Error in setting notification state for characteristic with UUID %@ on service with UUID %@ on peripheral with UUID %@",
515 [self CBUUIDToString:characteristic.UUID],
516 [self CBUUIDToString:characteristic.service.UUID],
517 peripheral.identifier.UUIDString);
518
519 NSLog(@"Error code was %s", [[error description] cStringUsingEncoding:NSStringEncodingConversionAllowLossy]);
520 }
521 }
522
523 - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
524 {
525 unsigned char data[20];
526
527 static unsigned char buf[512];
528 static int len = 0;
529 NSInteger data_len;
530
531 if (!error)
532 {
533 if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@RBL_CHAR_TX_UUID]])
534 {
535 data_len = characteristic.value.length;
536 [characteristic.value getBytes:data length:data_len];
537
538 if (data_len == 20)
539 {
540 memcpy(&buf[len], data, 20);
541 len += data_len;
542
543 if (len >= 64)
544 {
545 [[self delegate] bleDidReceiveData:buf length:len];
546 len = 0;
547 }
548 }
549 else if (data_len < 20)
550 {
551 memcpy(&buf[len], data, data_len);
552 len += data_len;
553
554 [[self delegate] bleDidReceiveData:buf length:len];
555 len = 0;
556 }
557 }
558 }
559 else
560 {
561 NSLog(@"updateValueForCharacteristic failed!");
562 }
563 }
564
565 - (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error
566 {
567 if (!isConnected)
568 return;
569
570 if (rssi != peripheral.RSSI.intValue)
571 {
572 rssi = peripheral.RSSI.intValue;
573 [[self delegate] bleDidUpdateRSSI:activePeripheral.RSSI];
574 }
575 }
576
577 @end
1
2 /*
3
4 Copyright (c) 2013-2014 RedBearLab
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7
8 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11
12 */
13
14 // RBL Service
15 #define RBL_SERVICE_UUID "713D0000-503E-4C75-BA94-3148F18D941E"
16 #define RBL_CHAR_TX_UUID "713D0002-503E-4C75-BA94-3148F18D941E"
17 #define RBL_CHAR_RX_UUID "713D0003-503E-4C75-BA94-3148F18D941E"
18
19 #define RBL_BLE_FRAMEWORK_VER 0x0200
1 //
2 // BootSettingController.h
3 // jacket_test_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/07/24.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10 #import "BleProtocol.h"
11 #import "BLE.h"
12
13 typedef enum {
14 EEPROM_WP_OFF,
15 EEPROM_WP_OFF_DONE,
16 EEPROM_WP_ON,
17 EEPROM_WP_ON_DONE,
18 FIRMWARE_IMAGE_SELECT_0,
19 FIRMWARE_IMAGE_SELECT_0_DONE,
20 FIRMWARE_IMAGE_SELECT_1,
21 FIRMWARE_IMAGE_SELECT_1_DONE,
22 RESET,
23 RESET_DONE,
24 DONE
25 } BootSettingBleCommandState;
26
27 @interface BootSettingController : UIViewController<BLEProtocolDelegate> {
28 BootSettingBleCommandState bleCommandState;
29 BootSettingBleCommandState bleCommandStateNext;
30 }
31
32 @property (strong, nonatomic) BleProtocol *protocol;
33 @property (nonatomic,assign) id <BLEProtocolDelegate> lastProtocolDelegate;
34
35 @end
1 //
2 // BootSettingController.m
3 // jacket_test_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/07/24.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "BootSettingController.h"
10
11 @interface BootSettingController ()
12
13 @end
14
15 @implementation BootSettingController
16
17 - (void)viewDidLoad {
18 [super viewDidLoad];
19 // Do any additional setup after loading the view from its nib.
20 }
21
22 - (void)didReceiveMemoryWarning {
23 [super didReceiveMemoryWarning];
24 // Dispose of any resources that can be recreated.
25 }
26
27 - (void)viewWillAppear:(BOOL)animated {
28 self.lastProtocolDelegate = self.protocol.delegate;
29 self.protocol.delegate = self;
30 }
31
32 - (void)viewWillDisappear:(BOOL)animated {
33 self.protocol.delegate = self.lastProtocolDelegate;
34 }
35
36 - (void)showAlert:(NSString*)title message:(NSString*)message{
37 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
38 message:message
39 delegate:self
40 cancelButtonTitle:@"OK"
41 otherButtonTitles:nil];
42 [alert show];
43 }
44
45 - (IBAction)cancelButtonClicked:(id)sender {
46 [self dismissViewControllerAnimated:YES completion:Nil];
47 }
48
49 /*
50 #pragma mark - Navigation
51
52 // In a storyboard-based application, you will often want to do a little preparation before navigation
53 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
54 // Get the new view controller using [segue destinationViewController].
55 // Pass the selected object to the new view controller.
56 }
57 */
58
59 - (IBAction)selectImage0Clicked:(id)sender {
60 bleCommandState = EEPROM_WP_OFF;
61 bleCommandStateNext = FIRMWARE_IMAGE_SELECT_0;
62
63 [self bleCommandTask];
64
65 NSLog(@"selectImage0Clicked done");
66 }
67
68 - (IBAction)selectImage1Clicked:(id)sender {
69 bleCommandState = EEPROM_WP_OFF;
70 bleCommandStateNext = FIRMWARE_IMAGE_SELECT_1;
71
72 [self bleCommandTask];
73
74 NSLog(@"selectImage0Clicked done");
75 }
76
77 - (BOOL)bleCommandTask {
78 switch(bleCommandState) {
79 case EEPROM_WP_OFF:
80 [[self protocol]putData:@"eepromWriteProtect" data:@"0"];
81 break;
82 case EEPROM_WP_OFF_DONE:
83 bleCommandState = bleCommandStateNext;
84 [self bleCommandTask];
85 break;
86 case EEPROM_WP_ON:
87 [[self protocol]putData:@"eepromWriteProtect" data:@"1"];
88 break;
89 case EEPROM_WP_ON_DONE:
90 bleCommandState = DONE;
91 [self bleCommandTask];
92 break;
93 case FIRMWARE_IMAGE_SELECT_0:
94 [[self protocol]putData:@"firmwareImageSelect" data:@"0"];
95 break;
96 case FIRMWARE_IMAGE_SELECT_0_DONE:
97 bleCommandState = EEPROM_WP_ON;
98 [self bleCommandTask];
99 break;
100 case FIRMWARE_IMAGE_SELECT_1:
101 [[self protocol]putData:@"firmwareImageSelect" data:@"1"];
102 break;
103 case FIRMWARE_IMAGE_SELECT_1_DONE:
104 bleCommandState = EEPROM_WP_ON;
105 [self bleCommandTask];
106 break;
107 case RESET:
108 [[self protocol]putData:@"systemReset" data:nil];
109 break;
110 case RESET_DONE:
111 {
112 NSLog(@"Ble command set done!");
113 break;
114 }
115 case DONE:
116 {
117 NSLog(@"Ble command set done!");
118 [self showAlert:@"EEPROM書き込み" message:@"EEPROMに保存しました。"];
119 break;
120 }
121 }
122 return false;
123 }
124
125 - (void)protocolDidGetData:(NSString *)dataType data:(NSString *)dataData {
126 if([dataType isEqualToString:@"firmwareImageSelect"]) {
127 if([dataData isEqualToString:@"0"]) {
128 NSLog(@"firmwareImageSelect 0");
129 bleCommandState = FIRMWARE_IMAGE_SELECT_0_DONE;
130 [self bleCommandTask];
131 } else if([dataData isEqualToString:@"1"]) {
132 NSLog(@"firmwareImageSelect 1");
133 bleCommandState = FIRMWARE_IMAGE_SELECT_1_DONE;
134 [self bleCommandTask];
135 }
136 } else if([dataType isEqualToString:@"eepromWriteProtect"]) {
137 if([dataData isEqualToString:@"0"]) {
138 NSLog(@"eepromWriteProtect 0");
139 bleCommandState = EEPROM_WP_OFF_DONE;
140 [self bleCommandTask];
141 } else if([dataData isEqualToString:@"1"]) {
142 NSLog(@"eepromWriteProtect 1");
143 bleCommandState = EEPROM_WP_ON_DONE;
144 [self bleCommandTask];
145 }
146 } else if([dataType isEqualToString:@"systemReset"]) {
147 NSLog(@"systemReset");
148 bleCommandState = RESET_DONE;
149 [self bleCommandTask];
150 }
151 }
152
153 @end
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
3 <device id="retina4_7" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <deployment identifier="iOS"/>
8 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
9 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10 </dependencies>
11 <objects>
12 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="BootSettingController">
13 <connections>
14 <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
15 </connections>
16 </placeholder>
17 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
18 <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
19 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
20 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
21 <subviews>
22 <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fTM-mh-INi">
23 <rect key="frame" x="0.0" y="23" width="375" height="44"/>
24 <items>
25 <navigationItem title="起動設定" id="gUm-My-XyB">
26 <barButtonItem key="leftBarButtonItem" title="戻る" id="FKk-cz-oNn">
27 <connections>
28 <action selector="cancelButtonClicked:" destination="-1" id="2WK-pK-yx1"/>
29 </connections>
30 </barButtonItem>
31 </navigationItem>
32 </items>
33 </navigationBar>
34 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LXt-Fp-Egr">
35 <rect key="frame" x="149" y="157" width="77" height="30"/>
36 <state key="normal" title="イメージ1"/>
37 <connections>
38 <action selector="selectImage1Clicked:" destination="-1" eventType="touchUpInside" id="3DN-JD-Fh5"/>
39 </connections>
40 </button>
41 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="xKp-zn-ktL">
42 <rect key="frame" x="95" y="97" width="184" height="30"/>
43 <state key="normal" title="ファームウェア更新モード"/>
44 <connections>
45 <action selector="selectImage0Clicked:" destination="-1" eventType="touchUpInside" id="Hfa-rm-ZOf"/>
46 </connections>
47 </button>
48 </subviews>
49 <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
50 <constraints>
51 <constraint firstItem="xKp-zn-ktL" firstAttribute="top" secondItem="fTM-mh-INi" secondAttribute="bottom" constant="30" id="1On-Cz-oFe"/>
52 <constraint firstItem="fTM-mh-INi" firstAttribute="centerX" secondItem="xKp-zn-ktL" secondAttribute="centerX" id="8Vf-o5-eah"/>
53 <constraint firstAttribute="trailing" secondItem="fTM-mh-INi" secondAttribute="trailing" id="9Fe-2W-A8G"/>
54 <constraint firstItem="xKp-zn-ktL" firstAttribute="centerX" secondItem="LXt-Fp-Egr" secondAttribute="centerX" id="N6N-OR-fWN"/>
55 <constraint firstItem="LXt-Fp-Egr" firstAttribute="top" secondItem="xKp-zn-ktL" secondAttribute="bottom" constant="30" id="ZOf-Ae-7hS"/>
56 <constraint firstItem="fTM-mh-INi" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="iZR-EP-iEa"/>
57 <constraint firstItem="xKp-zn-ktL" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="kul-HK-4Cd"/>
58 <constraint firstItem="fTM-mh-INi" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="23" id="m5P-3V-zcJ"/>
59 <constraint firstItem="LXt-Fp-Egr" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="wEs-z8-waM"/>
60 </constraints>
61 </view>
62 </objects>
63 </document>
1 //
2 // DBManager.h
3 // SQLite3DBSample
4 //
5 // Created by ドラッサル 亜嵐 on 2016/02/03.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <Foundation/Foundation.h>
10
11 @protocol DBManagerDelegate
12 @optional
13 - (void)gotData:(NSString *)data;
14 @required
15 @end
16
17 @interface DBManager : NSObject
18 @property (nonatomic,assign) id <DBManagerDelegate> delegate;
19 @property (nonatomic, strong) NSMutableArray *arrColumnNames;
20 @property (nonatomic) int affectedRows;
21 @property (nonatomic) long long lastInsertedRowID;
22
23 -(NSArray *)loadDataFromDB:(NSString *)query;
24 -(void)executeQuery:(NSString *)query;
25 - (NSArray*)getFirmwareDataList;
26 - (NSArray*)getEepromTemplateData;
27 - (bool)saveFirmwareData:(NSString *)uuid
28 deviceType:(NSString *)deviceType
29 deviceModel:(NSString *)deviceModel
30 version:(NSString *)version
31 versionStamp:(NSString *)versionStamp
32 file:(NSString *)file;
33 - (bool)saveEepromTemplateData:(NSString *)recordId
34 recordName:(NSString *)recordName
35 dataId:(NSString *)dataId
36 deviceModel:(NSString *)dataModel
37 dataType:(NSString *)dataType
38 dataOs:(NSString *)dataOs
39 dataPin:(NSString *)dataPin;
40 - (bool)deleteFirmwareData:(NSString *)recordId;
41 - (bool)deleteEepromTemplateData:(NSString *)recordId;
42
43 + (NSString*) createDatabaseIfRequiredAtPath:(NSString*)databasePath;
44
45 + (instancetype)sharedInstance;
46
47 @end
1 //
2 // DBManager.m
3 // SQLite3DBSample
4 //
5 // Created by ドラッサル 亜嵐 on 2016/02/03.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "DBManager.h"
10 #import <sqlite3.h>
11
12 @interface DBManager ()
13
14 @property (nonatomic, strong) NSString *documentsDirectory;
15 @property (nonatomic, strong) NSString *databaseFilename;
16 @property (nonatomic, strong) NSMutableArray *arrResults;
17
18
19 -(void)copyDatabaseIntoDocumentsDirectory;
20
21 -(void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable;
22
23 @end
24
25 @implementation DBManager {
26 NSLock* _lock;
27 }
28
29 + (NSString*) createDatabaseIfRequiredAtPath:(NSString*)databasePath {
30
31 if (databasePath == nil)
32 return nil;
33
34
35 //NSString *path = [NSString stringWithFormat:@"%@/%@", databasePath, kMainDBName];
36 NSString *path = [NSString stringWithFormat:@"%@/%@", databasePath, DATABASE];
37 NSFileManager *fileManager = [NSFileManager defaultManager];
38 NSError *error = nil;
39
40 if ([fileManager fileExistsAtPath:path] == NO)
41 {
42 // The writable database does not exist, so copy the default to the appropriate location.
43 //NSString *defaultDBPath = [[NSBundle mainBundle] pathForResource:kMainDBName
44 // ofType:nil];
45 NSString *defaultDBPath = [[NSBundle mainBundle] pathForResource:DATABASE
46 ofType:nil];
47 BOOL success = [fileManager copyItemAtPath:defaultDBPath
48 toPath:path
49 error:&error];
50 if (!success)
51 {
52 NSCAssert1(0, @"Failed to create writable database file with message '%@'.", [ error localizedDescription]);
53 return nil;
54 }
55 }
56
57 return path;
58 }
59
60 - (void)initFirst {
61 NSLog(@"[DBManager] initFirst");
62
63 // Set the documents directory path to the documentsDirectory property.
64 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
65 self.documentsDirectory = [paths objectAtIndex:0];
66
67 //NSString *dbFilenameFixed = [DBManager createDatabaseIfRequiredAtPath:dbFilename];
68 NSString *dbFilenameFixed = DATABASE;
69
70 // Keep the database filename.
71 self.databaseFilename = dbFilenameFixed;
72
73 // Copy the database file into the documents directory if necessary.
74 [self copyDatabaseIntoDocumentsDirectory];
75
76 // Create a sqlite object.
77 sqlite3 *sqlite3Database;
78
79 // Set the database file path.
80 NSString *databasePath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
81
82 // Open the database.
83 BOOL openDatabaseResult = sqlite3_open([databasePath UTF8String], &sqlite3Database);
84 if(openDatabaseResult == SQLITE_OK) {
85 const char *sqlStatement =
86 "CREATE TABLE IF NOT EXISTS FIRMWARE (ID INTEGER PRIMARY KEY, FIRMWARE_UUID TEXT, FIRMWARE_DEVICE_TYPE TEXT, FIRMWARE_DEVICE_MODEL TEXT, FIRMWARE_VERSION TEXT, FIRMWARE_VERSION_STAMP TEXT, FIRMWARE_FILE TEXT);"
87 "CREATE TABLE IF NOT EXISTS EEPROM_TEMPLATE (ID INTEGER PRIMARY KEY, EEPROM_TEMPLATE_NAME TEXT, EEPROM_TEMPLATE_ID TEXT, EEPROM_TEMPLATE_MODEL TEXT, EEPROM_TEMPLATE_TYPE TEXT, EEPROM_TEMPLATE_OS TEXT, EEPROM_TEMPLATE_PIN TEXT);";
88
89 char *error;
90
91 if(sqlite3_exec(sqlite3Database, sqlStatement, NULL, NULL, &error) == SQLITE_OK){
92 NSLog(@"All tables are created");
93 } else {
94 NSLog(@"Unable to create some table %s", error);
95 sqlite3_free(error);
96 error = NULL;
97 }
98 } else {
99 NSLog(@"Database creation error");
100 }
101
102 /* BEGIN insert column if needed */
103 NSString *query = @"PRAGMA table_info(EEPROM_TEMPLATE)";
104 NSArray *result = [self loadDataFromDB:query];
105
106 //NSLog(@"%@", result);
107
108 bool columnFoundEEPROM_TEMPLATE_PIN = false;
109
110 for(id key in result) {
111 NSLog(@"%@", [key objectAtIndex:1]);
112
113 if([[key objectAtIndex:1] isEqualToString:@"EEPROM_TEMPLATE_PIN"]) {
114 columnFoundEEPROM_TEMPLATE_PIN = true;
115 }
116
117 }
118
119 if(!columnFoundEEPROM_TEMPLATE_PIN) {
120 const char *sqlStatement =
121 "ALTER TABLE EEPROM_TEMPLATE ADD COLUMN EEPROM_TEMPLATE_PIN TEXT;";
122
123 char *error;
124
125 if(sqlite3_exec(sqlite3Database, sqlStatement, NULL, NULL, &error) == SQLITE_OK){
126 NSLog(@"All tables are altered");
127 } else {
128 NSLog(@"Unable to alter some table %s", error);
129 sqlite3_free(error);
130 error = NULL;
131 }
132 }
133
134 /* END insert column if needed */
135
136 // Close the database.
137 sqlite3_close(sqlite3Database);
138 }
139
140 -(void)copyDatabaseIntoDocumentsDirectory{
141 // Check if the database file exists in the documents directory.
142 NSString *destinationPath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
143 if (![[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
144 // The database file does not exist in the documents directory, so copy it from the main bundle now.
145 NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseFilename];
146 NSError *error;
147 [[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:destinationPath error:&error];
148
149 // Check if any error occurred during copying and display it.
150 if (error != nil) {
151 NSLog(@"%@", [error localizedDescription]);
152 }
153 }
154 }
155
156 -(void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable{
157 // Create a sqlite object.
158 sqlite3 *sqlite3Database;
159
160 // Set the database file path.
161 NSString *databasePath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
162
163 // Initialize the results array.
164 if (self.arrResults != nil) {
165 [self.arrResults removeAllObjects];
166 self.arrResults = nil;
167 }
168 self.arrResults = [[NSMutableArray alloc] init];
169
170 // Initialize the column names array.
171 if (self.arrColumnNames != nil) {
172 [self.arrColumnNames removeAllObjects];
173 self.arrColumnNames = nil;
174 }
175 self.arrColumnNames = [[NSMutableArray alloc] init];
176
177
178 // Open the database.
179 BOOL openDatabaseResult = sqlite3_open([databasePath UTF8String], &sqlite3Database);
180 if(openDatabaseResult == SQLITE_OK) {
181 // Declare a sqlite3_stmt object in which will be stored the query after having been compiled into a SQLite statement.
182 sqlite3_stmt *compiledStatement;
183
184 // Load all data from database to memory.
185 BOOL prepareStatementResult = sqlite3_prepare_v2(sqlite3Database, query, -1, &compiledStatement, NULL);
186 if(prepareStatementResult == SQLITE_OK) {
187 // Check if the query is non-executable.
188 if (!queryExecutable){
189 // In this case data must be loaded from the database.
190
191 // Declare an array to keep the data for each fetched row.
192 NSMutableArray *arrDataRow;
193
194 // Loop through the results and add them to the results array row by row.
195 while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
196 // Initialize the mutable array that will contain the data of a fetched row.
197 arrDataRow = [[NSMutableArray alloc] init];
198
199 // Get the total number of columns.
200 int totalColumns = sqlite3_column_count(compiledStatement);
201
202 // Go through all columns and fetch each column data.
203 for (int i=0; i<totalColumns; i++){
204 // Convert the column data to text (characters).
205 char *dbDataAsChars = (char *)sqlite3_column_text(compiledStatement, i);
206
207 // If there are contents in the currenct column (field) then add them to the current row array.
208 if (dbDataAsChars != NULL) {
209 // Convert the characters to string.
210 [arrDataRow addObject:[NSString stringWithUTF8String:dbDataAsChars]];
211 } else {
212 [arrDataRow addObject:@""];
213 }
214
215 // Keep the current column name.
216 if (self.arrColumnNames.count != totalColumns) {
217 dbDataAsChars = (char *)sqlite3_column_name(compiledStatement, i);
218 [self.arrColumnNames addObject:[NSString stringWithUTF8String:dbDataAsChars]];
219 }
220 }
221
222 // Store each fetched data row in the results array, but first check if there is actually data.
223 if (arrDataRow.count > 0) {
224 [self.arrResults addObject:arrDataRow];
225 }
226 }
227 }
228 else {
229 // This is the case of an executable query (insert, update, ...).
230
231 // Execute the query.
232 int executeQueryResults = sqlite3_step(compiledStatement);
233 if (executeQueryResults == SQLITE_DONE) {
234 // Keep the affected rows.
235 self.affectedRows = sqlite3_changes(sqlite3Database);
236
237 // Keep the last inserted row ID.
238 self.lastInsertedRowID = sqlite3_last_insert_rowid(sqlite3Database);
239 }
240 else {
241 // If could not execute the query show the error message on the debugger.
242 NSLog(@"DB Error: %s", sqlite3_errmsg(sqlite3Database));
243 }
244 }
245 }
246 else {
247 // In the database cannot be opened then show the error message on the debugger.
248 NSLog(@"%s", sqlite3_errmsg(sqlite3Database));
249 }
250
251 // Release the compiled statement from memory.
252 sqlite3_finalize(compiledStatement);
253
254 // Close the database.
255 sqlite3_close(sqlite3Database);
256 }
257 }
258
259 -(NSArray *)loadDataFromDB:(NSString *)query{
260 // Run the query and indicate that is not executable.
261 // The query string is converted to a char* object.
262 [self runQuery:[query UTF8String] isQueryExecutable:NO];
263
264 // Returned the loaded results.
265 return (NSArray *)self.arrResults;
266 }
267
268 -(void)executeQuery:(NSString *)query{
269 // Run the query and indicate that is executable.
270 [self runQuery:[query UTF8String] isQueryExecutable:YES];
271 }
272
273 - (NSArray*)getFirmwareDataList {
274 NSString *query = @"SELECT ID, FIRMWARE_UUID, FIRMWARE_DEVICE_TYPE, FIRMWARE_DEVICE_MODEL, FIRMWARE_VERSION, FIRMWARE_VERSION_STAMP, FIRMWARE_FILE FROM FIRMWARE";
275 NSArray *result = [self loadDataFromDB:query];
276 return result;
277 }
278
279 - (NSArray*)getEepromTemplateData {
280 NSString *query = @"SELECT ID, EEPROM_TEMPLATE_NAME, EEPROM_TEMPLATE_ID, EEPROM_TEMPLATE_MODEL, EEPROM_TEMPLATE_TYPE, EEPROM_TEMPLATE_OS, EEPROM_TEMPLATE_PIN FROM EEPROM_TEMPLATE";
281 NSArray *result = [self loadDataFromDB:query];
282 return result;
283 }
284
285 - (bool)saveFirmwareData:(NSString *)uuid
286 deviceType:(NSString *)deviceType
287 deviceModel:(NSString *)deviceModel
288 version:(NSString *)version
289 versionStamp:(NSString *)versionStamp
290 file:(NSString *)file
291 {
292 NSString *queryCheck = [NSString stringWithFormat:@"SELECT FIRMWARE_UUID FROM FIRMWARE WHERE FIRMWARE_UUID = '%@'",uuid];
293 NSArray *queryCheckResult = [self loadDataFromDB:queryCheck];
294 if([queryCheckResult count] != 0) {
295 NSString *queryUpdate = [NSString stringWithFormat:@"UPDATE FIRMWARE SET FIRMWARE_DEVICE_MODEL = '%@', FIRMWARE_DEVICE_TYPE = '%@', FIRMWARE_VERSION = '%@', FIRMWARE_VERSION_STAMP = '%@', FIRMWARE_FILE = '%@' WHERE FIRMWARE_UUID = '%@'",deviceType,deviceModel,version,versionStamp,file,uuid];
296 [self executeQuery:queryUpdate];
297 } else {
298 NSString *queryInsert = [NSString stringWithFormat:@"INSERT INTO FIRMWARE (FIRMWARE_UUID, FIRMWARE_DEVICE_TYPE, FIRMWARE_DEVICE_MODEL, FIRMWARE_VERSION, FIRMWARE_VERSION_STAMP, FIRMWARE_FILE) VALUES ('%@','%@','%@','%@','%@','%@')",uuid, deviceType, deviceModel, version, versionStamp, file];
299 [self executeQuery:queryInsert];
300 }
301 return true;
302 }
303
304 - (bool)saveEepromTemplateData:(NSString *)recordId
305 recordName:(NSString *)recordName
306 dataId:(NSString *)dataId
307 deviceModel:(NSString *)dataModel
308 dataType:(NSString *)dataType
309 dataOs:(NSString *)dataOs
310 dataPin:(NSString *)dataPin
311 {
312 NSString *queryCheck = [NSString stringWithFormat:@"SELECT ID FROM EEPROM_TEMPLATE WHERE ID = '%@'",recordId];
313 NSArray *queryCheckResult = [self loadDataFromDB:queryCheck];
314 if([queryCheckResult count] != 0) {
315 NSString *queryUpdate = [NSString stringWithFormat:@"UPDATE EEPROM_TEMPLATE SET EEPROM_TEMPLATE_NAME = '%@', EEPROM_TEMPLATE_ID = '%@', EEPROM_TEMPLATE_MODEL = '%@', EEPROM_TEMPLATE_TYPE = '%@', EEPROM_TEMPLATE_OS = '%@', EEPROM_TEMPLATE_PIN = '%@', WHERE ID = '%@'",recordName, dataId, dataModel, dataType, dataOs, dataPin, recordId];
316 [self executeQuery:queryUpdate];
317 } else {
318 NSString *queryInsert = [NSString stringWithFormat:@"INSERT INTO EEPROM_TEMPLATE (EEPROM_TEMPLATE_NAME, EEPROM_TEMPLATE_ID, EEPROM_TEMPLATE_MODEL, EEPROM_TEMPLATE_TYPE, EEPROM_TEMPLATE_OS, EEPROM_TEMPLATE_PIN) VALUES ('%@','%@','%@','%@','%@','%@')",recordName, dataId, dataModel, dataType, dataOs, dataPin];
319 [self executeQuery:queryInsert];
320 }
321 return true;
322 }
323
324 - (bool)deleteFirmwareData:(NSString *)recordId {
325 NSString *queryDelete = [NSString stringWithFormat:@"DELETE FROM FIRMWARE WHERE ID = '%@'",recordId];
326 [self executeQuery:queryDelete];
327 return true;
328 }
329
330 - (bool)deleteEepromTemplateData:(NSString *)recordId {
331 NSString *queryDelete = [NSString stringWithFormat:@"DELETE FROM EEPROM_TEMPLATE WHERE ID = '%@'",recordId];
332 [self executeQuery:queryDelete];
333 return true;
334 }
335
336 - (BOOL)checkForField:(NSString *)tblName colName:(NSString *)colName {
337 // Create a sqlite object.
338 sqlite3 *sqlite3Database;
339
340 // Set the database file path.
341 NSString *databasePath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
342
343 // Open the database.
344 BOOL openDatabaseResult = sqlite3_open([databasePath UTF8String], &sqlite3Database);
345 if(openDatabaseResult == SQLITE_OK) {
346
347 NSString *sql = [NSString stringWithFormat:@"PRAGMA table_info(%@)", tblName];
348 sqlite3_stmt *stmt;
349
350 if (sqlite3_prepare_v2(sqlite3Database, [sql UTF8String], -1, &stmt, NULL) != SQLITE_OK)
351 {
352 return NO;
353 }
354
355 while(sqlite3_step(stmt) == SQLITE_ROW)
356 {
357 NSString *fieldName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(stmt, 1)];
358 if([colName isEqualToString:fieldName]) {
359 // Close the database.
360 sqlite3_close(sqlite3Database);
361 return YES;
362 }
363 }
364 // Close the database.
365 sqlite3_close(sqlite3Database);
366 }
367 return NO;
368 }
369
370 /*
371 #pragma mark - Navigation
372
373 // In a storyboard-based application, you will often want to do a little preparation before navigation
374 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
375 // Get the new view controller using [segue destinationViewController].
376 // Pass the selected object to the new view controller.
377 }
378 */
379
380 # pragma mark - Singleton pattern
381
382 static DBManager *_sharedInstance;
383
384 - (instancetype)init {
385 @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"[Operation] Use 'sharedInstance' instead of 'init' as this class is singleton." userInfo:nil];
386 }
387
388 + (instancetype)sharedInstance {
389 @synchronized(self) {
390 if (_sharedInstance == nil) {
391 (void) [[self alloc] initPrivate]; // ここでは代入していない
392 }
393 }
394 return _sharedInstance;
395 }
396
397 - (instancetype)initPrivate {
398 self = [super init];
399 if (self) {
400 // 初期処理
401 _lock = [[NSLock alloc] init];
402 [self initFirst];
403 }
404 return self;
405 }
406
407 + (id)allocWithZone:(NSZone *)zone {
408 @synchronized(self) {
409 if (_sharedInstance == nil) {
410 _sharedInstance = [super allocWithZone:zone];
411 return _sharedInstance; // 最初の割り当てで代入し、返す
412 }
413 }
414 return nil;
415 }
416
417 - (id)copyWithZone:(NSZone *)zone {
418 return self;
419 }
420
421 @end
1 //
2 // DemoView.swift
3 // jacket_test_ios
4 //
5 // Created by USER on 2017/10/11.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 import UIKit
10
11 class DemoView: UIView {
12
13
14 // Only override draw() if you perform custom drawing.
15 // An empty implementation adversely affects performance during animation.
16 override func draw(_ rect: CGRect) {
17 // Drawing code
18 let label = UILabel()
19 label.text = "Demo"
20 label.sizeToFit()
21 self.addSubview(label)
22
23 }
24
25
26 }
1 //
2 // EepromController.h
3 // jacket_test_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/07/24.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10 #import "BleProtocol.h"
11 #import "BLE.h"
12 #import "EepromTemplateController.h"
13
14 typedef enum {
15 EEPROM__EEPROM_WP_OFF,
16 EEPROM__EEPROM_WP_OFF_DONE,
17 EEPROM__EEPROM_WP_ON,
18 EEPROM__EEPROM_WP_ON_DONE,
19 EEPROM__EEPROM_READ_ID,
20 EEPROM__EEPROM_READ_ID_DONE,
21 EEPROM__EEPROM_READ_MODEL,
22 EEPROM__EEPROM_READ_MODEL_DONE,
23 EEPROM__EEPROM_READ_TYPE,
24 EEPROM__EEPROM_READ_TYPE_DONE,
25 EEPROM__EEPROM_READ_OS,
26 EEPROM__EEPROM_READ_OS_DONE,
27 EEPROM__EEPROM_READ_PIN,
28 EEPROM__EEPROM_READ_PIN_DONE,
29 EEPROM__EEPROM_WRITE_ID,
30 EEPROM__EEPROM_WRITE_ID_DONE,
31 EEPROM__EEPROM_WRITE_MODEL,
32 EEPROM__EEPROM_WRITE_MODEL_DONE,
33 EEPROM__EEPROM_WRITE_TYPE,
34 EEPROM__EEPROM_WRITE_TYPE_DONE,
35 EEPROM__EEPROM_WRITE_OS,
36 EEPROM__EEPROM_WRITE_OS_DONE,
37 EEPROM__EEPROM_WRITE_PIN,
38 EEPROM__EEPROM_WRITE_PIN_DONE,
39 EEPROM__DONE
40 } EepromCommandState;
41
42 @interface EepromController : UIViewController<EepromTemplateControllerDelegate, BLEProtocolDelegate> {
43 IBOutlet UITextField *txtId;
44 IBOutlet UITextField *txtModel;
45 IBOutlet UITextField *txtType;
46 IBOutlet UITextField *txtOs;
47 IBOutlet UITextField *txtPin;
48 NSString *strId;
49 NSString *strModel;
50 NSString *strType;
51 NSString *strOs;
52 NSString *strPin;
53 EepromCommandState bleCommandState;
54 IBOutlet UIScrollView *scrollView;
55 UITextField *activeField;
56 }
57
58 - (IBAction)cancelButtonClicked:(id)sender;
59 - (IBAction)saveButtonClicked:(id)sender;
60
61 @property (strong, nonatomic) BleProtocol *protocol;
62 @property (nonatomic,assign) id <BLEProtocolDelegate> lastProtocolDelegate;
63
64 @end
1 //
2 // EepromController.m
3 // jacket_test_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/07/24.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "EepromController.h"
10 #import "EepromTemplateController.h"
11 #import "DBManager.h"
12
13 @interface EepromController ()
14
15 @end
16
17 @implementation EepromController
18
19 - (void)viewDidLoad {
20 [super viewDidLoad];
21
22 //The setup code (in viewDidLoad in your view controller)
23 UITapGestureRecognizer *singleFingerTap =
24 [[UITapGestureRecognizer alloc] initWithTarget:self
25 action:@selector(handleSingleTap:)];
26 [self.view addGestureRecognizer:singleFingerTap];
27
28 // Do any additional setup after loading the view from its nib.
29
30 txtId.text = @"";
31 txtModel.text = @"";
32 txtType.text = @"";
33 txtOs.text = @"";
34 txtPin.text = @"";
35
36 bleCommandState = EEPROM__EEPROM_READ_ID;
37 [self bleCommandTask];
38 }
39
40 - (void)viewWillAppear:(BOOL)animated {
41 [self registerForKeyboardNotifications];
42 self.lastProtocolDelegate = self.protocol.delegate;
43 self.protocol.delegate = self;
44 }
45
46 - (void)viewWillDisappear:(BOOL)animated {
47 [self unregisterFromKeyboardNotifications];
48 self.protocol.delegate = self.lastProtocolDelegate;
49 }
50
51 - (void)showAlert:(NSString*)title message:(NSString*)message{
52 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
53 message:message
54 delegate:self
55 cancelButtonTitle:@"OK"
56 otherButtonTitles:nil];
57 [alert show];
58 }
59
60 // Call this method somewhere in your view controller setup code.
61 - (void)registerForKeyboardNotifications
62 {
63 [[NSNotificationCenter defaultCenter] addObserver:self
64 selector:@selector(keyboardWasShown:)
65 name:UIKeyboardDidShowNotification object:nil];
66
67 [[NSNotificationCenter defaultCenter] addObserver:self
68 selector:@selector(keyboardWillBeHidden:)
69 name:UIKeyboardWillHideNotification object:nil];
70
71 }
72
73 - (void)unregisterFromKeyboardNotifications
74 {
75 /*
76 [[NSNotificationCenter defaultCenter] addObserver:self
77 selector:@selector(keyboardWasShown:)
78 name:UIKeyboardDidShowNotification object:nil];
79
80 [[NSNotificationCenter defaultCenter] addObserver:self
81 selector:@selector(keyboardWillBeHidden:)
82 name:UIKeyboardWillHideNotification object:nil];
83 */
84
85 }
86
87 // Called when the UIKeyboardWillHideNotification is sent
88 - (void)keyboardWillBeHidden:(NSNotification*)aNotification
89 {
90 UIEdgeInsets contentInsets = UIEdgeInsetsZero;
91 scrollView.contentInset = contentInsets;
92 scrollView.scrollIndicatorInsets = contentInsets;
93 }
94
95 - (void)textFieldDidBeginEditing:(UITextField *)textField
96 {
97 activeField = textField;
98 }
99
100 - (void)textFieldDidEndEditing:(UITextField *)textField
101 {
102 activeField = nil;
103 }
104
105 // Called when the UIKeyboardDidShowNotification is sent.
106 - (void)keyboardWasShown:(NSNotification*)aNotification
107 {
108 NSDictionary* info = [aNotification userInfo];
109 CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
110
111 UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
112 scrollView.contentInset = contentInsets;
113 scrollView.scrollIndicatorInsets = contentInsets;
114
115 // If active text field is hidden by keyboard, scroll it so it's visible
116 // Your app might not need or want this behavior.
117 CGRect aRect = self.view.frame;
118 aRect.size.height -= kbSize.height;
119 if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
120 [scrollView scrollRectToVisible:activeField.frame animated:YES];
121 }
122 }
123 /*
124 There are other ways you can scroll the edited area in a scroll view above an obscuring keyboard. Instead of altering the bottom content inset of the scroll view, you can extend the height of the content view by the height of the keyboard and then scroll the edited text object into view. Although the UIScrollView class has a contentSize property that you can set for this purpose, you can also adjust the frame of the content view, as shown in Listing 4-3. This code also uses the setContentOffset:animated: method to scroll the edited field into view, in this case scrolling it just above the top of the keyboard.
125 */
126 /*
127 - (void)keyboardWasShown:(NSNotification*)aNotification {
128 NSDictionary* info = [aNotification userInfo];
129 CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
130 CGRect bkgndRect = activeField.superview.frame;
131 bkgndRect.size.height += kbSize.height;
132 [activeField.superview setFrame:bkgndRect];
133 [scrollView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height) animated:YES];
134 }
135 */
136 //The event handling method
137 - (void)handleSingleTap:(UITapGestureRecognizer *)recognizer
138 {
139 //CGPoint location = [recognizer locationInView:[recognizer.view superview]];
140
141 //Do stuff here...
142 [self.view endEditing:YES];
143 }
144
145 - (void)didReceiveMemoryWarning {
146 [super didReceiveMemoryWarning];
147 // Dispose of any resources that can be recreated.
148 }
149
150 - (IBAction)cancelButtonClicked:(id)sender {
151 [self dismissViewControllerAnimated:YES completion:Nil];
152 }
153
154 - (IBAction)saveButtonClicked:(id)sender {
155 bleCommandState = EEPROM__EEPROM_WP_OFF;
156 [self bleCommandTask];
157 }
158
159 - (IBAction)resetButtonClicked:(id)sender {
160 txtId.text = @"";
161 txtModel.text = @"";
162 txtType.text = @"";
163 txtOs.text = @"";
164
165 bleCommandState = EEPROM__EEPROM_READ_ID;
166 [self bleCommandTask];
167 }
168
169 - (IBAction)templateLoadButtonClicked:(id)sender {
170 EepromTemplateController *viewObj=[[EepromTemplateController alloc] initWithNibName:@"EepromTemplateController" bundle:nil];
171 viewObj.delegate = self;
172 [self presentViewController:viewObj animated:YES completion: nil];
173 }
174
175 - (IBAction)templateSaveButtonClicked:(id)sender {
176 UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Title"
177 message:nil
178 preferredStyle:UIAlertControllerStyleAlert];
179 [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
180 // optionally configure the text field
181 textField.keyboardType = UIKeyboardTypeAlphabet;
182 }];
183
184 UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"キャンセル"
185 style:UIAlertActionStyleDefault
186 handler:^(UIAlertAction *action) {
187 UITextField *textField = [alert.textFields firstObject];
188 textField.placeholder = @"Enter Input";
189 }];
190 [alert addAction:cancelAction];
191
192 UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"保存"
193 style:UIAlertActionStyleDefault
194 handler:^(UIAlertAction *action) {
195 UITextField *textField = [alert.textFields firstObject];
196 textField.placeholder = @"Enter Input";
197 [self clickedSaveNameInput:textField.text];
198 }];
199 [alert addAction:okAction];
200 [self presentViewController:alert animated:YES completion:nil];
201 }
202
203 - (void)clickedSaveNameInput:(NSString *)textFieldText {
204 NSLog(@"clickedSaveNameInput:'%@'",textFieldText);
205
206 NSString *dataIdText = txtId.text;
207 NSString *dataModelText = txtModel.text;
208 NSString *dataTypeText = txtType.text;
209 NSString *dataOsText = txtOs.text;
210 NSString *dataPinText = txtPin.text;
211
212 [[DBManager sharedInstance] saveEepromTemplateData:nil
213 recordName:textFieldText
214 dataId:dataIdText
215 deviceModel:dataModelText
216 dataType:dataTypeText
217 dataOs:dataOsText
218 dataPin:dataPinText];
219 }
220
221 - (void)didChoose:(NSString *)recordId
222 recordName:(NSString *)recordName
223 dataId:(NSString *)dataId
224 dataModel:(NSString *)dataModel
225 dataType:(NSString *)dataType
226 dataOs:(NSString *)dataOs
227 dataPin:(NSString *)dataPin {
228 txtId.text = dataId;
229 txtModel.text = dataModel;
230 txtType.text = dataType;
231 txtOs.text = dataOs;
232 txtPin.text = dataPin;
233 }
234
235 - (BOOL)bleCommandTask {
236 switch(bleCommandState) {
237 case EEPROM__EEPROM_WP_OFF:
238 [[self protocol]putData:@"eepromWriteProtect" data:@"0"];
239 break;
240 case EEPROM__EEPROM_WP_OFF_DONE:
241 bleCommandState = EEPROM__EEPROM_WRITE_ID;
242 [self bleCommandTask];
243 break;
244 case EEPROM__EEPROM_WP_ON:
245 [[self protocol]putData:@"eepromWriteProtect" data:@"1"];
246 break;
247 case EEPROM__EEPROM_WP_ON_DONE:
248 bleCommandState = EEPROM__DONE;
249 [self bleCommandTask];
250 break;
251 case EEPROM__EEPROM_READ_ID:
252 [[self protocol]putData:@"readDeviceId" data:nil];
253 break;
254 case EEPROM__EEPROM_READ_MODEL:
255 [[self protocol]putData:@"readDeviceModel" data:nil];
256 break;
257 case EEPROM__EEPROM_READ_TYPE:
258 [[self protocol]putData:@"readDeviceType" data:nil];
259 break;
260 case EEPROM__EEPROM_READ_OS:
261 [[self protocol]putData:@"readDeviceOs" data:nil];
262 break;
263 case EEPROM__EEPROM_READ_PIN:
264 [[self protocol]putData:@"readDevicePin" data:nil];
265 break;
266 case EEPROM__EEPROM_READ_ID_DONE:
267 bleCommandState = EEPROM__EEPROM_READ_MODEL;
268 [self bleCommandTask];
269 break;
270 case EEPROM__EEPROM_READ_MODEL_DONE:
271 bleCommandState = EEPROM__EEPROM_READ_TYPE;
272 [self bleCommandTask];
273 break;
274 case EEPROM__EEPROM_READ_TYPE_DONE:
275 bleCommandState = EEPROM__EEPROM_READ_OS;
276 [self bleCommandTask];
277 break;
278 case EEPROM__EEPROM_READ_OS_DONE:
279 bleCommandState = EEPROM__EEPROM_READ_PIN;
280 [self bleCommandTask];
281 break;
282 case EEPROM__EEPROM_READ_PIN_DONE:
283 bleCommandState = EEPROM__DONE;
284 [self bleCommandTask];
285 break;
286 case EEPROM__EEPROM_WRITE_ID:
287 if(![strId isEqualToString:txtId.text]) {
288 [[self protocol]putData:@"writeDeviceId" data:txtId.text];
289 } else {
290 bleCommandState = EEPROM__EEPROM_WRITE_ID_DONE;
291 [self bleCommandTask];
292 }
293 break;
294 case EEPROM__EEPROM_WRITE_MODEL:
295 if(![strModel isEqualToString:txtModel.text]) {
296 [[self protocol]putData:@"writeDeviceModel" data:txtModel.text];
297 } else {
298 bleCommandState = EEPROM__EEPROM_WRITE_MODEL_DONE;
299 [self bleCommandTask];
300 }
301 break;
302 case EEPROM__EEPROM_WRITE_TYPE:
303 if(![strType isEqualToString:txtType.text]) {
304 [[self protocol]putData:@"writeDeviceType" data:txtType.text];
305 } else {
306 bleCommandState = EEPROM__EEPROM_WRITE_TYPE_DONE;
307 [self bleCommandTask];
308 }
309 break;
310 case EEPROM__EEPROM_WRITE_OS:
311 if(![strOs isEqualToString:txtOs.text]) {
312 [[self protocol]putData:@"writeDeviceOs" data:txtOs.text];
313 } else {
314 bleCommandState = EEPROM__EEPROM_WRITE_OS_DONE;
315 [self bleCommandTask];
316 }
317 break;
318 case EEPROM__EEPROM_WRITE_PIN:
319 if(![strOs isEqualToString:txtPin.text]) {
320 [[self protocol]putData:@"writeDevicePin" data:txtPin.text];
321 } else {
322 bleCommandState = EEPROM__EEPROM_WRITE_PIN_DONE;
323 [self bleCommandTask];
324 }
325 break;
326 case EEPROM__EEPROM_WRITE_ID_DONE:
327 bleCommandState = EEPROM__EEPROM_WRITE_MODEL;
328 [self bleCommandTask];
329 break;
330 case EEPROM__EEPROM_WRITE_MODEL_DONE:
331 bleCommandState = EEPROM__EEPROM_WRITE_TYPE;
332 [self bleCommandTask];
333 break;
334 case EEPROM__EEPROM_WRITE_TYPE_DONE:
335 bleCommandState = EEPROM__EEPROM_WRITE_OS;
336 [self bleCommandTask];
337 break;
338 case EEPROM__EEPROM_WRITE_OS_DONE:
339 bleCommandState = EEPROM__EEPROM_WRITE_PIN;
340 [self bleCommandTask];
341 break;
342 case EEPROM__EEPROM_WRITE_PIN_DONE:
343 bleCommandState = EEPROM__EEPROM_WP_ON;
344 [self showAlert:@"EEPROM書き込み" message:@"EEPROMに保存しました。"];
345 [self bleCommandTask];
346 break;
347 case EEPROM__DONE:
348 {
349 NSLog(@"Ble command set done!");
350 break;
351 }
352 }
353 return false;
354 }
355
356 - (void)protocolDidGetData:(NSString *)dataType data:(NSString *)dataData {
357 if([dataType isEqualToString:@"eepromWriteProtect"]) {
358 if([dataData isEqualToString:@"0"]) {
359 NSLog(@"eepromWriteProtect 0");
360 bleCommandState = EEPROM__EEPROM_WP_OFF_DONE;
361 [self bleCommandTask];
362 } else if([dataData isEqualToString:@"1"]) {
363 NSLog(@"eepromWriteProtect 1");
364 bleCommandState = EEPROM__EEPROM_WP_ON_DONE;
365 [self bleCommandTask];
366 }
367 } else if([dataType isEqualToString:@"readDeviceId"]) {
368 NSLog(@"infoDeviceId");
369 strId = dataData;
370 txtId.text = dataData;
371 bleCommandState = EEPROM__EEPROM_READ_ID_DONE;
372 [self bleCommandTask];
373 } else if([dataType isEqualToString:@"readDeviceModel"]) {
374 NSLog(@"infoDeviceModel");
375 strModel = dataData;
376 txtModel.text = dataData;
377 bleCommandState = EEPROM__EEPROM_READ_MODEL_DONE;
378 [self bleCommandTask];
379 } else if([dataType isEqualToString:@"readDeviceType"]) {
380 NSLog(@"infoDeviceType");
381 strType = dataData;
382 txtType.text = dataData;
383 bleCommandState = EEPROM__EEPROM_READ_TYPE_DONE;
384 [self bleCommandTask];
385 } else if([dataType isEqualToString:@"readDeviceOs"]) {
386 NSLog(@"infoDeviceOs");
387 strOs = dataData;
388 txtOs.text = dataData;
389 bleCommandState = EEPROM__EEPROM_READ_OS_DONE;
390 [self bleCommandTask];
391 } else if([dataType isEqualToString:@"readDevicePin"]) {
392 NSLog(@"infoDevicePin");
393 strPin = dataData;
394 txtPin.text = dataData;
395 bleCommandState = EEPROM__EEPROM_READ_PIN_DONE;
396 [self bleCommandTask];
397 } else if([dataType isEqualToString:@"writeDeviceId"]) {
398 NSLog(@"writeDeviceId");
399 bleCommandState = EEPROM__EEPROM_WRITE_ID_DONE;
400 [self bleCommandTask];
401 } else if([dataType isEqualToString:@"writeDeviceModel"]) {
402 NSLog(@"writeDeviceModel");
403 bleCommandState = EEPROM__EEPROM_WRITE_MODEL_DONE;
404 [self bleCommandTask];
405 } else if([dataType isEqualToString:@"writeDeviceType"]) {
406 NSLog(@"writeDeviceType");
407 bleCommandState = EEPROM__EEPROM_WRITE_TYPE_DONE;
408 [self bleCommandTask];
409 } else if([dataType isEqualToString:@"writeDeviceOs"]) {
410 NSLog(@"writeDeviceOs");
411 bleCommandState = EEPROM__EEPROM_WRITE_OS_DONE;
412 [self bleCommandTask];
413 } else if([dataType isEqualToString:@"writeDevicePin"]) {
414 NSLog(@"writeDevicePin");
415 bleCommandState = EEPROM__EEPROM_WRITE_PIN_DONE;
416 [self bleCommandTask];
417 }
418 }
419
420 /*
421 #pragma mark - Navigation
422
423 // In a storyboard-based application, you will often want to do a little preparation before navigation
424 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
425 // Get the new view controller using [segue destinationViewController].
426 // Pass the selected object to the new view controller.
427 }
428 */
429
430 @end
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
3 <device id="retina4_0" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <deployment identifier="iOS"/>
8 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
9 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10 </dependencies>
11 <objects>
12 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="EepromController">
13 <connections>
14 <outlet property="scrollView" destination="Qfe-fH-Hfv" id="lXM-aQ-FXJ"/>
15 <outlet property="txtId" destination="jmd-K8-5dg" id="ec5-oZ-Y0Z"/>
16 <outlet property="txtModel" destination="pY8-yj-AoT" id="0fs-fo-dhx"/>
17 <outlet property="txtOs" destination="NgZ-hI-GtN" id="BPP-0p-OEY"/>
18 <outlet property="txtPin" destination="8hP-og-fMY" id="Fip-no-OYL"/>
19 <outlet property="txtType" destination="fHz-BN-gtb" id="IJ2-JN-Jx2"/>
20 <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
21 </connections>
22 </placeholder>
23 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
24 <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
25 <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
26 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
27 <subviews>
28 <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IfS-pJ-JXb">
29 <rect key="frame" x="0.0" y="23" width="320" height="44"/>
30 <items>
31 <navigationItem title="EEPROM設定" id="GLk-is-6zE">
32 <barButtonItem key="leftBarButtonItem" title="戻る" id="IQj-B6-LM1">
33 <connections>
34 <action selector="cancelButtonClicked:" destination="-1" id="o3Y-f5-6x4"/>
35 </connections>
36 </barButtonItem>
37 <barButtonItem key="rightBarButtonItem" title="保存" id="mdn-zs-McT">
38 <connections>
39 <action selector="saveButtonClicked:" destination="-1" id="sks-Kk-yBR"/>
40 </connections>
41 </barButtonItem>
42 </navigationItem>
43 </items>
44 </navigationBar>
45 <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Qfe-fH-Hfv">
46 <rect key="frame" x="0.0" y="67" width="320" height="501"/>
47 <subviews>
48 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Y4h-pJ-JSj" userLabel="Content">
49 <rect key="frame" x="0.0" y="0.0" width="320" height="502"/>
50 <subviews>
51 <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="jmd-K8-5dg">
52 <rect key="frame" x="20" y="49" width="288" height="30"/>
53 <nil key="textColor"/>
54 <fontDescription key="fontDescription" type="system" pointSize="14"/>
55 <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
56 </textField>
57 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ID" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Q7T-oe-kRb">
58 <rect key="frame" x="20" y="20" width="17" height="21"/>
59 <fontDescription key="fontDescription" type="system" pointSize="17"/>
60 <nil key="textColor"/>
61 <nil key="highlightedColor"/>
62 </label>
63 <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="pY8-yj-AoT">
64 <rect key="frame" x="20" y="128" width="288" height="30"/>
65 <nil key="textColor"/>
66 <fontDescription key="fontDescription" type="system" pointSize="14"/>
67 <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
68 </textField>
69 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="MODEL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hIO-x4-poN">
70 <rect key="frame" x="20" y="99" width="59" height="21"/>
71 <fontDescription key="fontDescription" type="system" pointSize="17"/>
72 <nil key="textColor"/>
73 <nil key="highlightedColor"/>
74 </label>
75 <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="fHz-BN-gtb">
76 <rect key="frame" x="20" y="207" width="288" height="30"/>
77 <nil key="textColor"/>
78 <fontDescription key="fontDescription" type="system" pointSize="14"/>
79 <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
80 </textField>
81 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="TYPE" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YHb-SQ-GZw">
82 <rect key="frame" x="20" y="178" width="42" height="21"/>
83 <fontDescription key="fontDescription" type="system" pointSize="17"/>
84 <nil key="textColor"/>
85 <nil key="highlightedColor"/>
86 </label>
87 <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="NgZ-hI-GtN">
88 <rect key="frame" x="20" y="288" width="288" height="30"/>
89 <nil key="textColor"/>
90 <fontDescription key="fontDescription" type="system" pointSize="14"/>
91 <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
92 </textField>
93 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="OS" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yOB-oe-lIs">
94 <rect key="frame" x="20" y="259" width="24" height="21"/>
95 <fontDescription key="fontDescription" type="system" pointSize="17"/>
96 <nil key="textColor"/>
97 <nil key="highlightedColor"/>
98 </label>
99 <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="8hP-og-fMY">
100 <rect key="frame" x="20" y="368" width="288" height="30"/>
101 <nil key="textColor"/>
102 <fontDescription key="fontDescription" type="system" pointSize="14"/>
103 <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
104 </textField>
105 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="PIN" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="svC-S5-7yd">
106 <rect key="frame" x="20" y="339" width="27" height="21"/>
107 <fontDescription key="fontDescription" type="system" pointSize="17"/>
108 <nil key="textColor"/>
109 <nil key="highlightedColor"/>
110 </label>
111 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6T6-T4-HhO">
112 <rect key="frame" x="188" y="408" width="46" height="30"/>
113 <state key="normal" title="セーブ"/>
114 <connections>
115 <action selector="templateSaveButtonClicked:" destination="-1" eventType="touchUpInside" id="tf6-8x-hyl"/>
116 </connections>
117 </button>
118 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8Je-bg-zen">
119 <rect key="frame" x="133" y="452" width="62" height="30"/>
120 <state key="normal" title="リセット"/>
121 <connections>
122 <action selector="resetButtonClicked:" destination="-1" eventType="touchUpInside" id="4nK-yx-4Tm"/>
123 </connections>
124 </button>
125 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yAu-89-NQb">
126 <rect key="frame" x="93" y="408" width="46" height="30"/>
127 <state key="normal" title="ロード"/>
128 <connections>
129 <action selector="templateLoadButtonClicked:" destination="-1" eventType="touchUpInside" id="BvH-XD-IaO"/>
130 </connections>
131 </button>
132 </subviews>
133 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
134 <constraints>
135 <constraint firstItem="Q7T-oe-kRb" firstAttribute="leading" secondItem="jmd-K8-5dg" secondAttribute="leading" id="34q-kf-sRF"/>
136 <constraint firstItem="fHz-BN-gtb" firstAttribute="trailing" secondItem="NgZ-hI-GtN" secondAttribute="trailing" id="7a4-LL-5B7"/>
137 <constraint firstItem="NgZ-hI-GtN" firstAttribute="leading" secondItem="svC-S5-7yd" secondAttribute="leading" id="9QZ-KW-Eag"/>
138 <constraint firstItem="pY8-yj-AoT" firstAttribute="top" secondItem="hIO-x4-poN" secondAttribute="bottom" constant="8" symbolic="YES" id="BJp-me-e5P"/>
139 <constraint firstItem="svC-S5-7yd" firstAttribute="top" secondItem="NgZ-hI-GtN" secondAttribute="bottom" constant="21" id="C8k-pf-wpT"/>
140 <constraint firstItem="8hP-og-fMY" firstAttribute="top" secondItem="svC-S5-7yd" secondAttribute="bottom" constant="8" symbolic="YES" id="D9W-LK-na6"/>
141 <constraint firstItem="yAu-89-NQb" firstAttribute="top" secondItem="8hP-og-fMY" secondAttribute="bottom" constant="10" id="FxX-iZ-wVQ"/>
142 <constraint firstItem="yOB-oe-lIs" firstAttribute="leading" secondItem="NgZ-hI-GtN" secondAttribute="leading" id="GTw-Qo-h9f"/>
143 <constraint firstItem="8Je-bg-zen" firstAttribute="top" secondItem="yAu-89-NQb" secondAttribute="bottom" constant="14" id="JPc-Ak-yre"/>
144 <constraint firstItem="Q7T-oe-kRb" firstAttribute="leading" secondItem="Y4h-pJ-JSj" secondAttribute="leading" constant="20" id="LFx-zF-3cm"/>
145 <constraint firstItem="YHb-SQ-GZw" firstAttribute="leading" secondItem="fHz-BN-gtb" secondAttribute="leading" id="LhX-9v-mA6"/>
146 <constraint firstItem="hIO-x4-poN" firstAttribute="top" secondItem="jmd-K8-5dg" secondAttribute="bottom" constant="20" id="Lu9-1B-Meu"/>
147 <constraint firstItem="jmd-K8-5dg" firstAttribute="top" secondItem="Q7T-oe-kRb" secondAttribute="bottom" constant="8" symbolic="YES" id="SiJ-qx-AAu"/>
148 <constraint firstItem="pY8-yj-AoT" firstAttribute="trailing" secondItem="fHz-BN-gtb" secondAttribute="trailing" id="VdP-zv-qpf"/>
149 <constraint firstItem="jmd-K8-5dg" firstAttribute="leading" secondItem="hIO-x4-poN" secondAttribute="leading" id="WSX-p0-Nud"/>
150 <constraint firstItem="fHz-BN-gtb" firstAttribute="leading" secondItem="yOB-oe-lIs" secondAttribute="leading" id="X09-ii-JR1"/>
151 <constraint firstItem="yOB-oe-lIs" firstAttribute="top" secondItem="fHz-BN-gtb" secondAttribute="bottom" constant="22" id="Zw5-us-oKD"/>
152 <constraint firstItem="8hP-og-fMY" firstAttribute="centerX" secondItem="8Je-bg-zen" secondAttribute="centerX" id="c31-8u-MDo"/>
153 <constraint firstItem="Q7T-oe-kRb" firstAttribute="top" secondItem="Y4h-pJ-JSj" secondAttribute="top" constant="20" id="d6Q-gG-PmN"/>
154 <constraint firstItem="svC-S5-7yd" firstAttribute="leading" secondItem="8hP-og-fMY" secondAttribute="leading" id="eEd-Cl-6lf"/>
155 <constraint firstItem="yAu-89-NQb" firstAttribute="leading" secondItem="Y4h-pJ-JSj" secondAttribute="leading" constant="93" id="hB6-yF-fsK"/>
156 <constraint firstItem="yAu-89-NQb" firstAttribute="baseline" secondItem="6T6-T4-HhO" secondAttribute="baseline" id="hVI-o6-fOE"/>
157 <constraint firstItem="pY8-yj-AoT" firstAttribute="leading" secondItem="YHb-SQ-GZw" secondAttribute="leading" id="i34-ti-Ng1"/>
158 <constraint firstItem="hIO-x4-poN" firstAttribute="leading" secondItem="pY8-yj-AoT" secondAttribute="leading" id="kQY-so-a1C"/>
159 <constraint firstItem="NgZ-hI-GtN" firstAttribute="trailing" secondItem="8hP-og-fMY" secondAttribute="trailing" id="lER-6n-iNx"/>
160 <constraint firstItem="6T6-T4-HhO" firstAttribute="leading" secondItem="yAu-89-NQb" secondAttribute="trailing" constant="49" id="nK6-hC-Xte"/>
161 <constraint firstItem="NgZ-hI-GtN" firstAttribute="top" secondItem="yOB-oe-lIs" secondAttribute="bottom" constant="8" symbolic="YES" id="nwc-fP-zwh"/>
162 <constraint firstAttribute="trailing" secondItem="jmd-K8-5dg" secondAttribute="trailing" constant="12" id="omi-XO-Quv"/>
163 <constraint firstItem="YHb-SQ-GZw" firstAttribute="top" secondItem="pY8-yj-AoT" secondAttribute="bottom" constant="20" id="pvD-8w-rx7"/>
164 <constraint firstItem="fHz-BN-gtb" firstAttribute="top" secondItem="YHb-SQ-GZw" secondAttribute="bottom" constant="8" symbolic="YES" id="yx3-pV-wHX"/>
165 <constraint firstItem="jmd-K8-5dg" firstAttribute="trailing" secondItem="pY8-yj-AoT" secondAttribute="trailing" id="zW1-dc-xfs"/>
166 </constraints>
167 </view>
168 </subviews>
169 <constraints>
170 <constraint firstAttribute="bottom" secondItem="Y4h-pJ-JSj" secondAttribute="bottom" id="BBM-HT-Vbq"/>
171 <constraint firstAttribute="trailing" secondItem="Y4h-pJ-JSj" secondAttribute="trailing" id="FyK-gd-Via"/>
172 <constraint firstItem="Y4h-pJ-JSj" firstAttribute="centerY" secondItem="Qfe-fH-Hfv" secondAttribute="centerY" id="Gue-mo-e3c"/>
173 <constraint firstItem="Y4h-pJ-JSj" firstAttribute="top" secondItem="Qfe-fH-Hfv" secondAttribute="top" id="NGn-wv-7da"/>
174 <constraint firstItem="Y4h-pJ-JSj" firstAttribute="centerX" secondItem="Qfe-fH-Hfv" secondAttribute="centerX" id="YLA-PQ-YfF"/>
175 <constraint firstItem="Y4h-pJ-JSj" firstAttribute="leading" secondItem="Qfe-fH-Hfv" secondAttribute="leading" id="maX-xJ-VPb"/>
176 </constraints>
177 </scrollView>
178 </subviews>
179 <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
180 <constraints>
181 <constraint firstItem="IfS-pJ-JXb" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="23" id="1yP-fd-d6Y"/>
182 <constraint firstItem="IfS-pJ-JXb" firstAttribute="leading" secondItem="Qfe-fH-Hfv" secondAttribute="leading" id="Epr-ZY-vqh"/>
183 <constraint firstItem="IfS-pJ-JXb" firstAttribute="trailing" secondItem="Qfe-fH-Hfv" secondAttribute="trailing" id="PZF-lX-b4H"/>
184 <constraint firstItem="IfS-pJ-JXb" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="ZZM-xe-gxx"/>
185 <constraint firstItem="Qfe-fH-Hfv" firstAttribute="top" secondItem="IfS-pJ-JXb" secondAttribute="bottom" id="i0o-qh-JSM"/>
186 <constraint firstAttribute="bottom" secondItem="Qfe-fH-Hfv" secondAttribute="bottom" id="neI-1C-ByC"/>
187 <constraint firstAttribute="trailing" secondItem="IfS-pJ-JXb" secondAttribute="trailing" id="zoy-gH-9sf"/>
188 </constraints>
189 <point key="canvasLocation" x="24" y="52"/>
190 </view>
191 </objects>
192 </document>
1 //
2 // EepromTemplateController.h
3 // jacket_test_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/07/24.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10
11 @protocol EepromTemplateControllerDelegate
12 @optional
13 - (void)didChoose:(NSString *)recordId
14 recordName:(NSString *)recordName
15 dataId:(NSString *)dataId
16 dataModel:(NSString *)dataModel
17 dataType:(NSString *)dataType
18 dataOs:(NSString *)dataOs
19 dataPin:(NSString *)dataPin;
20 @required
21 @end
22
23 @interface EepromTemplateController : UIViewController<UITableViewDelegate, UITableViewDataSource> {
24 IBOutlet UITableView *tblResult;
25 NSMutableArray *arrResult;
26 }
27
28 @property (nonatomic,assign) id <EepromTemplateControllerDelegate> delegate;
29
30 @end
1 //
2 // EepromTemplateController.m
3 // jacket_test_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/07/24.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "EepromTemplateController.h"
10 #import "EepromTemplateTableViewCell.h"
11 #import "DBManager.h"
12
13 @interface EepromTemplateController ()
14
15 @end
16
17 @implementation EepromTemplateController
18
19 - (void)viewDidLoad {
20 [super viewDidLoad];
21 // Do any additional setup after loading the view from its nib.
22 }
23
24 - (void)viewWillAppear:(BOOL)animated {
25 arrResult = [[NSMutableArray alloc] init];
26
27 UINib *nib = [UINib nibWithNibName:@"EepromTemplateTableViewCell" bundle:nil];
28 [tblResult registerNib:nib forCellReuseIdentifier:@"mycell"];
29 tblResult.delegate = self;
30 tblResult.dataSource = self;
31
32 [arrResult removeAllObjects];
33
34 NSArray *result = [[DBManager sharedInstance] getEepromTemplateData];
35
36 for(id key in result) {
37 NSString *valueRecordId = [key objectAtIndex:0];
38 NSString *valueRecordName = [key objectAtIndex:1];
39 NSString *valueDataId = [key objectAtIndex:2];
40 NSString *valueDataModel = [key objectAtIndex:3];
41 NSString *valueDataType = [key objectAtIndex:4];
42 NSString *valueDataOs = [key objectAtIndex:5];
43 NSString *valueDataPin = [key objectAtIndex:6];
44
45 NSMutableDictionary *newDict = [NSMutableDictionary dictionary];
46 [newDict setObject:valueRecordId forKey:@"recordId"];
47 [newDict setObject:valueRecordName forKey:@"recordName"];
48 [newDict setObject:valueDataId forKey:@"dataId"];
49 [newDict setObject:valueDataModel forKey:@"dataModel"];
50 [newDict setObject:valueDataType forKey:@"dataType"];
51 [newDict setObject:valueDataOs forKey:@"dataOs"];
52 [newDict setObject:valueDataPin forKey:@"dataPin"];
53
54 [arrResult addObject:newDict];
55 }
56 [tblResult reloadData];
57 }
58
59 - (void)didReceiveMemoryWarning {
60 [super didReceiveMemoryWarning];
61 // Dispose of any resources that can be recreated.
62 }
63
64 - (IBAction)cancelButtonClicked:(id)sender {
65 [self dismissViewControllerAnimated:YES completion:Nil];
66 }
67
68 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
69 NSInteger row = [indexPath row];
70 NSDictionary *dataRecord = [arrResult objectAtIndex:row];
71
72 [self.delegate didChoose:[dataRecord valueForKey:@"recordId"]
73 recordName:[dataRecord valueForKey:@"recordName"]
74 dataId:[dataRecord valueForKey:@"dataId"]
75 dataModel:[dataRecord valueForKey:@"dataModel"]
76 dataType:[dataRecord valueForKey:@"dataType"]
77 dataOs:[dataRecord valueForKey:@"dataOs"]
78 dataPin:[dataRecord valueForKey:@"dataPin"]];
79 [self dismissViewControllerAnimated:YES completion:Nil];
80 }
81
82 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
83 // Return the number of sections.
84 return 1;
85 }
86
87 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
88 // Return the number of rows in the section.
89 return [arrResult count];
90 }
91
92 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
93 {
94 static NSString *cellIdentifier = @"mycell";
95 EepromTemplateTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
96
97 NSInteger row = [indexPath row];
98 NSDictionary *dataRecord = [arrResult objectAtIndex:row];
99
100 // Configure the cell...
101 UIFont *newFont = [UIFont fontWithName:@"Arial" size:17.0];
102 cell.lblRecordName.font = newFont;
103 cell.lblRecordName.text = [dataRecord valueForKey:@"recordName"];
104
105 newFont = [UIFont fontWithName:@"Arial" size:12.0];
106 cell.lblRecordId.font = newFont;
107 cell.lblRecordId.text = [dataRecord valueForKey:@"recordId"];
108
109 cell.lblDataId.font = newFont;
110 cell.lblDataId.text = [dataRecord valueForKey:@"dataId"];
111
112 cell.lblDataModel.font = newFont;
113 cell.lblDataModel.text = [dataRecord valueForKey:@"dataModel"];
114
115 cell.lblDataType.font = newFont;
116 cell.lblDataType.text = [dataRecord valueForKey:@"dataType"];
117
118 cell.lblDataOs.font = newFont;
119 cell.lblDataOs.text = [dataRecord valueForKey:@"dataOs"];
120
121 cell.lblDataPin.font = newFont;
122 cell.lblDataPin.text = [dataRecord valueForKey:@"dataPin"];
123
124 return cell;
125 }
126
127 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
128 {
129 return 100;
130 }
131
132 - (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
133 {
134 return @[
135 [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive
136 title:@"削除"
137 handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
138 // own delete action
139
140
141 // Distructive button tapped.
142 NSLog(@"削除の確認");
143
144 NSDictionary * selectedData = [arrResult objectAtIndex:indexPath.row];
145 NSString *firmwareTitle = [selectedData valueForKey:@"file"];
146
147 UIAlertController *actionSheetConfirm = [UIAlertController alertControllerWithTitle:@"削除の確認" message:[NSString stringWithFormat:@"「%@」を削除します。よろしいですか?",firmwareTitle] preferredStyle:UIAlertControllerStyleAlert];
148
149 [actionSheetConfirm addAction:[UIAlertAction actionWithTitle:@"削除" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *actionConfirm) {
150
151
152 // Get the record ID of the selected name and set it to the recordIDToEdit property.
153 NSDictionary * selectedData = [arrResult objectAtIndex:indexPath.row];
154
155 NSString *recordId = [selectedData valueForKey:@"recordId"];
156 NSLog(@"recordId = %@",recordId);
157
158 [[DBManager sharedInstance] deleteEepromTemplateData:recordId];
159 //[self populateDetail];
160 //[self.tblResult reloadData];
161 [arrResult removeObjectAtIndex:indexPath.row];
162 [tblResult deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
163 }]];
164 [actionSheetConfirm addAction:[UIAlertAction actionWithTitle:@"キャンセル" style:UIAlertActionStyleDefault handler:^(UIAlertAction *actionConfirm) {
165 // Distructive button tapped.
166 NSLog(@"キャンセルの確認");
167 }]];
168 [self presentViewController:actionSheetConfirm animated:YES completion:nil];
169 }],
170 ];
171 }
172
173 /*
174 #pragma mark - Navigation
175
176 // In a storyboard-based application, you will often want to do a little preparation before navigation
177 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
178 // Get the new view controller using [segue destinationViewController].
179 // Pass the selected object to the new view controller.
180 }
181 */
182
183 @end
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
3 <device id="retina4_7" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <deployment identifier="iOS"/>
8 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
9 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10 </dependencies>
11 <objects>
12 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="EepromTemplateController">
13 <connections>
14 <outlet property="tblResult" destination="ApV-bw-Rn1" id="zPh-Vf-P8V"/>
15 <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
16 </connections>
17 </placeholder>
18 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
19 <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
20 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
21 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
22 <subviews>
23 <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tFr-RW-xCk">
24 <rect key="frame" x="0.0" y="23" width="375" height="44"/>
25 <items>
26 <navigationItem title="テンプレート選択" id="9cH-Zh-eej">
27 <barButtonItem key="leftBarButtonItem" title="戻る" id="u5c-K3-4uI">
28 <connections>
29 <action selector="cancelButtonClicked:" destination="-1" id="45e-6T-qfA"/>
30 </connections>
31 </barButtonItem>
32 </navigationItem>
33 </items>
34 </navigationBar>
35 <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="ApV-bw-Rn1">
36 <rect key="frame" x="0.0" y="67" width="375" height="600"/>
37 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
38 </tableView>
39 </subviews>
40 <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
41 <constraints>
42 <constraint firstItem="tFr-RW-xCk" firstAttribute="leading" secondItem="ApV-bw-Rn1" secondAttribute="leading" id="4cX-M9-u63"/>
43 <constraint firstItem="tFr-RW-xCk" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="23" id="6cd-hA-zhv"/>
44 <constraint firstAttribute="bottom" secondItem="ApV-bw-Rn1" secondAttribute="bottom" id="9Qe-KE-6Ho"/>
45 <constraint firstItem="tFr-RW-xCk" firstAttribute="trailing" secondItem="ApV-bw-Rn1" secondAttribute="trailing" id="FXl-z1-bN7"/>
46 <constraint firstItem="tFr-RW-xCk" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="NGB-Xr-cIf"/>
47 <constraint firstAttribute="trailing" secondItem="tFr-RW-xCk" secondAttribute="trailing" id="ZyS-Vn-LV4"/>
48 <constraint firstItem="ApV-bw-Rn1" firstAttribute="top" secondItem="tFr-RW-xCk" secondAttribute="bottom" id="ad4-Qe-Nod"/>
49 </constraints>
50 <point key="canvasLocation" x="24.5" y="52.5"/>
51 </view>
52 </objects>
53 </document>
1 //
2 // EepromTemplateTableViewCell.h
3 // jacket_test_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/07/24.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10
11 @interface EepromTemplateTableViewCell : UITableViewCell
12
13 @property (strong, nonatomic) IBOutlet UILabel *lblRecordId;
14 @property (strong, nonatomic) IBOutlet UILabel *lblRecordName;
15 @property (strong, nonatomic) IBOutlet UILabel *lblDataId;
16 @property (strong, nonatomic) IBOutlet UILabel *lblDataModel;
17 @property (strong, nonatomic) IBOutlet UILabel *lblDataType;
18 @property (strong, nonatomic) IBOutlet UILabel *lblDataOs;
19 @property (strong, nonatomic) IBOutlet UILabel *lblDataPin;
20
21 @end
1 //
2 // EepromTemplateTableViewCell.m
3 // jacket_test_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/07/24.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "EepromTemplateTableViewCell.h"
10
11 @implementation EepromTemplateTableViewCell
12 @synthesize lblRecordId = _lblRecordId;
13 @synthesize lblRecordName = _lblRecordName;
14 @synthesize lblDataId = _lblDataId;
15 @synthesize lblDataModel = _lblDataModel;
16 @synthesize lblDataType = _lblDataType;
17 @synthesize lblDataOs = _lblDataOs;
18 @synthesize lblDataPin = _lblDataPin;
19
20 - (void)awakeFromNib {
21 [super awakeFromNib];
22 // Initialization code
23 }
24
25 - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
26 [super setSelected:selected animated:animated];
27
28 // Configure the view for the selected state
29 }
30
31 @end
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
3 <device id="retina4_7" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <deployment identifier="iOS"/>
8 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
9 <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
10 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
11 </dependencies>
12 <objects>
13 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
14 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
15 <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="100" id="KGk-i7-Jjw" customClass="EepromTemplateTableViewCell">
16 <rect key="frame" x="0.0" y="0.0" width="320" height="100"/>
17 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
18 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
19 <rect key="frame" x="0.0" y="0.0" width="320" height="99.5"/>
20 <autoresizingMask key="autoresizingMask"/>
21 <subviews>
22 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="recordId" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8fS-9z-HJ1">
23 <rect key="frame" x="8" y="0.0" width="304" height="15"/>
24 <fontDescription key="fontDescription" type="system" pointSize="12"/>
25 <nil key="textColor"/>
26 <nil key="highlightedColor"/>
27 </label>
28 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="dataId" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ehd-h0-G5F">
29 <rect key="frame" x="8" y="30" width="304" height="14.5"/>
30 <fontDescription key="fontDescription" type="system" pointSize="12"/>
31 <nil key="textColor"/>
32 <nil key="highlightedColor"/>
33 </label>
34 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="dataModel" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Gwb-VU-QNL">
35 <rect key="frame" x="8" y="44" width="304" height="14.5"/>
36 <fontDescription key="fontDescription" type="system" pointSize="12"/>
37 <nil key="textColor"/>
38 <nil key="highlightedColor"/>
39 </label>
40 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="dataType" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Gc3-Sq-C9l">
41 <rect key="frame" x="8" y="58" width="304" height="14.5"/>
42 <fontDescription key="fontDescription" type="system" pointSize="12"/>
43 <nil key="textColor"/>
44 <nil key="highlightedColor"/>
45 </label>
46 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="dataOs" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="458-dR-dVU">
47 <rect key="frame" x="8" y="71" width="304" height="14.5"/>
48 <fontDescription key="fontDescription" type="system" pointSize="12"/>
49 <nil key="textColor"/>
50 <nil key="highlightedColor"/>
51 </label>
52 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="recordName" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iT0-XG-TUh">
53 <rect key="frame" x="8" y="12" width="304" height="21"/>
54 <fontDescription key="fontDescription" type="system" pointSize="17"/>
55 <nil key="textColor"/>
56 <nil key="highlightedColor"/>
57 </label>
58 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="dataPin" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eOf-Vq-Ned">
59 <rect key="frame" x="8" y="83" width="43" height="15"/>
60 <fontDescription key="fontDescription" type="system" pointSize="12"/>
61 <nil key="textColor"/>
62 <nil key="highlightedColor"/>
63 </label>
64 </subviews>
65 <constraints>
66 <constraint firstItem="Gwb-VU-QNL" firstAttribute="top" secondItem="iT0-XG-TUh" secondAttribute="bottom" constant="11" id="3Ah-wp-nlD"/>
67 <constraint firstAttribute="trailingMargin" secondItem="458-dR-dVU" secondAttribute="trailing" id="3q1-IV-Uu4"/>
68 <constraint firstItem="458-dR-dVU" firstAttribute="top" secondItem="Gwb-VU-QNL" secondAttribute="bottom" constant="12.5" id="662-hh-xov"/>
69 <constraint firstAttribute="trailingMargin" secondItem="Gc3-Sq-C9l" secondAttribute="trailing" id="87s-sY-8PO"/>
70 <constraint firstItem="8fS-9z-HJ1" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" id="95Q-rK-8K6"/>
71 <constraint firstItem="ehd-h0-G5F" firstAttribute="top" secondItem="8fS-9z-HJ1" secondAttribute="bottom" constant="15" id="LQ7-1v-xOY"/>
72 <constraint firstAttribute="trailingMargin" secondItem="Gwb-VU-QNL" secondAttribute="trailing" id="NcB-sA-bvl"/>
73 <constraint firstItem="iT0-XG-TUh" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" constant="4" id="QJJ-js-QYu"/>
74 <constraint firstItem="ehd-h0-G5F" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" id="RC0-Ar-tZX"/>
75 <constraint firstItem="iT0-XG-TUh" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" id="VkX-0A-hRU"/>
76 <constraint firstItem="Gwb-VU-QNL" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" id="Vzs-yL-Pmn"/>
77 <constraint firstItem="eOf-Vq-Ned" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="8" id="Xaf-Xh-Ozw"/>
78 <constraint firstItem="Gc3-Sq-C9l" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" id="bQ8-Fy-ebk"/>
79 <constraint firstItem="Gc3-Sq-C9l" firstAttribute="top" secondItem="ehd-h0-G5F" secondAttribute="bottom" constant="13.5" id="bTK-je-YxG"/>
80 <constraint firstItem="458-dR-dVU" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" id="d0r-nI-b5G"/>
81 <constraint firstAttribute="trailingMargin" secondItem="iT0-XG-TUh" secondAttribute="trailing" id="htH-3d-fAh"/>
82 <constraint firstAttribute="trailingMargin" secondItem="8fS-9z-HJ1" secondAttribute="trailing" id="iRy-KW-NVN"/>
83 <constraint firstItem="eOf-Vq-Ned" firstAttribute="top" secondItem="Gc3-Sq-C9l" secondAttribute="bottom" constant="10.5" id="lNL-bx-aIK"/>
84 <constraint firstAttribute="trailingMargin" secondItem="ehd-h0-G5F" secondAttribute="trailing" id="mwI-LD-DKm"/>
85 <constraint firstItem="8fS-9z-HJ1" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="ygd-9l-fh7"/>
86 </constraints>
87 </tableViewCellContentView>
88 <connections>
89 <outlet property="lblDataId" destination="ehd-h0-G5F" id="zNI-oH-grq"/>
90 <outlet property="lblDataModel" destination="Gwb-VU-QNL" id="UfO-sd-eLM"/>
91 <outlet property="lblDataOs" destination="458-dR-dVU" id="RBV-15-xGE"/>
92 <outlet property="lblDataPin" destination="eOf-Vq-Ned" id="5fK-t6-Guw"/>
93 <outlet property="lblDataType" destination="Gc3-Sq-C9l" id="G49-kF-3gj"/>
94 <outlet property="lblRecordId" destination="8fS-9z-HJ1" id="oAa-nz-13w"/>
95 <outlet property="lblRecordName" destination="iT0-XG-TUh" id="LAb-QQ-lFu"/>
96 </connections>
97 <point key="canvasLocation" x="25" y="80"/>
98 </tableViewCell>
99 </objects>
100 </document>
1 //
2 // FirmwareDownloadController.h
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/06/06.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10 #import "BleProtocol.h"
11
12 typedef enum {
13 FIRMWARE_DOWNLOAD__EEPROM_READ_ID,
14 FIRMWARE_DOWNLOAD__EEPROM_READ_ID_DONE,
15 FIRMWARE_DOWNLOAD__EEPROM_READ_MODEL,
16 FIRMWARE_DOWNLOAD__EEPROM_READ_MODEL_DONE,
17 FIRMWARE_DOWNLOAD__EEPROM_READ_TYPE,
18 FIRMWARE_DOWNLOAD__EEPROM_READ_TYPE_DONE,
19 FIRMWARE_DOWNLOAD__EEPROM_READ_OS,
20 FIRMWARE_DOWNLOAD__EEPROM_READ_OS_DONE,
21 FIRMWARE_DOWNLOAD__DONE
22 } FirmwareDownloadCommandState;
23
24 @interface FirmwareDownloadController : UIViewController<UITableViewDelegate, UITableViewDataSource, BLEProtocolDelegate> {
25 IBOutlet UITableView *tblFirmware;
26 IBOutlet UILabel *lblPercentComplete;
27 NSMutableArray *arrResult;
28 int selectionEnabled;
29
30 NSString *strId;
31 NSString *strModel;
32 NSString *strType;
33 NSString *strOs;
34 FirmwareDownloadCommandState bleCommandState;
35 }
36
37 @property (strong, nonatomic) BleProtocol *protocol;
38 @property (nonatomic,assign) id <BLEProtocolDelegate> lastProtocolDelegate;
39
40 @end
1 //
2 // FirmwareDownloadController.m
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/06/06.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "FirmwareDownloadController.h"
10 #import "FirmwareDownloadControllerTableViewCell.h"
11 #import "Operation.h"
12 #import "DBManager.h"
13
14 @interface FirmwareDownloadController ()
15
16 @end
17
18 @implementation FirmwareDownloadController
19
20 - (void)viewDidLoad {
21 [super viewDidLoad];
22 // Do any additional setup after loading the view from its nib.
23 }
24
25 - (void)viewWillAppear:(BOOL)animated {
26 self.lastProtocolDelegate = self.protocol.delegate;
27 self.protocol.delegate = self;
28
29 bleCommandState = FIRMWARE_DOWNLOAD__EEPROM_READ_ID;
30 [self bleCommandTask];
31 }
32
33 - (void)viewWillDisappear:(BOOL)animated {
34 self.protocol.delegate = self.lastProtocolDelegate;
35 }
36
37 - (void)didReceiveMemoryWarning {
38 [super didReceiveMemoryWarning];
39 // Dispose of any resources that can be recreated.
40 }
41
42 - (void) getDownloadList {
43 selectionEnabled = 1;
44
45 arrResult = [[NSMutableArray alloc] init];
46
47 UINib *nib = [UINib nibWithNibName:@"FirmwareDownloadControllerTableViewCell" bundle:nil];
48 [tblFirmware registerNib:nib forCellReuseIdentifier:@"mycell"];
49 tblFirmware.delegate = self;
50 tblFirmware.dataSource = self;
51
52 [[Operation sharedOperation] getFirmwareList:strId
53 deviceType:strType
54 deviceModel:strModel
55 deviceOs:strOs
56 appVersion:@"appVersion"
57 success:^(id JSON) {
58 NSLog(@"SUCCESS!");
59
60 if([JSON valueForKey:@"firmware_list"]) {
61 [arrResult removeAllObjects];
62
63 NSDictionary *firmwareList = [JSON valueForKey:@"firmware_list"];
64
65 for(id selectedKey in firmwareList) {
66 NSDictionary *firmwareListRecord = [firmwareList valueForKey:selectedKey];
67 NSMutableDictionary *detailDict = [[NSMutableDictionary alloc] init];
68 [detailDict setValue:selectedKey forKey:@"uuid"];
69 for(id selectedSubKey in firmwareListRecord) {
70 [detailDict setValue:[firmwareListRecord valueForKey:selectedSubKey] forKey:selectedSubKey];
71 }
72 [arrResult addObject:detailDict];
73 }
74 }
75 [tblFirmware reloadData];
76 } failure:^(NSError *error, id JSON) {
77 NSLog(@"FAIL!");
78 }];
79 }
80
81 - (IBAction)cancelButtonClicked:(id)sender {
82 [self dismissViewControllerAnimated:YES completion:Nil];
83 }
84
85 - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
86 if(selectionEnabled == 1) {
87 return indexPath;
88 } else {
89 return nil;
90 }
91 }
92
93 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
94 NSInteger row = [indexPath row];
95 NSDictionary *dataRecord = [arrResult objectAtIndex:row];
96
97 NSString *filename = [dataRecord valueForKey:@"uuid"];
98
99 selectionEnabled = 0;
100
101 [[Operation sharedOperation] streamToFile:[NSString stringWithFormat:@"%@%@",URL_BASE,[NSString stringWithFormat:URL_PATH_STORE_FIRMWARE, filename]]
102 saveToPath:[NSString stringWithFormat:@"save/%@",filename]
103 progressBlock:^(double fractionCompleted) {
104 //NSLog(@"Progress: %f", fractionCompleted);
105 lblPercentComplete.text = [NSString stringWithFormat:@"%f%%", fractionCompleted * 100];
106 }
107 success:^(NSString *savedTo) {
108 NSLog(@"Saved to %@",savedTo);
109 [[DBManager sharedInstance] saveFirmwareData:[dataRecord valueForKey:@"uuid"]
110 deviceType:[dataRecord valueForKey:@"devicetype"]
111 deviceModel:[dataRecord valueForKey:@"devicemodel"]
112 version:[dataRecord valueForKey:@"version"]
113 versionStamp:[dataRecord valueForKey:@"version_Stamp"]
114 file:[dataRecord valueForKey:@"file"]];
115 //[self saveVideoInfo:video.identifier videoItag:[NSString stringWithFormat:@"%@",videoQuality] videoFilename:[NSString stringWithFormat:@"%@_%@.mp4",video.identifier,videoQuality]];
116 //[self showAlert:@"アプリに保存" message:@"保存完了"];
117 selectionEnabled = 1;
118 lblPercentComplete.text = @"完了";
119 }
120 failure:^(NSError *error) {
121 //[self showAlert:@"アプリに保存" message:@"保存完了"];
122 selectionEnabled = 1;
123 lblPercentComplete.text = @"失敗";
124 }];
125 }
126
127 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
128 // Return the number of sections.
129 return 1;
130 }
131
132 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
133 // Return the number of rows in the section.
134 return [arrResult count];
135 }
136
137 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
138 {
139 static NSString *cellIdentifier = @"mycell";
140 FirmwareDownloadControllerTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
141
142 NSInteger row = [indexPath row];
143 NSDictionary *dataRecord = [arrResult objectAtIndex:row];
144
145 // Configure the cell...
146 UIFont *newFont = [UIFont fontWithName:@"Arial" size:11.0];
147 cell.lblTitle.font = newFont;
148 cell.lblTitle.text = [dataRecord valueForKey:@"file"];
149
150 newFont = [UIFont fontWithName:@"Arial" size:11.0];
151 cell.lblSubtitle.font = newFont;
152 cell.lblSubtitle.text = [dataRecord valueForKey:@"uuid"];
153
154 return cell;
155 }
156
157 - (BOOL)bleCommandTask {
158 switch(bleCommandState) {
159 case FIRMWARE_DOWNLOAD__EEPROM_READ_ID:
160 [[self protocol]putData:@"infoDeviceId" data:nil];
161 break;
162 case FIRMWARE_DOWNLOAD__EEPROM_READ_MODEL:
163 [[self protocol]putData:@"infoDeviceModel" data:nil];
164 break;
165 case FIRMWARE_DOWNLOAD__EEPROM_READ_TYPE:
166 [[self protocol]putData:@"infoDeviceType" data:nil];
167 break;
168 case FIRMWARE_DOWNLOAD__EEPROM_READ_OS:
169 [[self protocol]putData:@"infoDeviceOs" data:nil];
170 break;
171 case FIRMWARE_DOWNLOAD__EEPROM_READ_ID_DONE:
172 bleCommandState = FIRMWARE_DOWNLOAD__EEPROM_READ_MODEL;
173 [self bleCommandTask];
174 break;
175 case FIRMWARE_DOWNLOAD__EEPROM_READ_MODEL_DONE:
176 bleCommandState = FIRMWARE_DOWNLOAD__EEPROM_READ_TYPE;
177 [self bleCommandTask];
178 break;
179 case FIRMWARE_DOWNLOAD__EEPROM_READ_TYPE_DONE:
180 bleCommandState = FIRMWARE_DOWNLOAD__EEPROM_READ_OS;
181 [self bleCommandTask];
182 break;
183 case FIRMWARE_DOWNLOAD__EEPROM_READ_OS_DONE:
184 bleCommandState = FIRMWARE_DOWNLOAD__DONE;
185 [self bleCommandTask];
186 break;
187 case FIRMWARE_DOWNLOAD__DONE:
188 {
189 NSLog(@"Ble command set done!");
190 [self getDownloadList];
191 break;
192 }
193 }
194 return false;
195 }
196
197 - (void)protocolDidGetData:(NSString *)dataType data:(NSString *)dataData {
198 if([dataType isEqualToString:@"infoDeviceId"]) {
199 NSLog(@"infoDeviceId");
200 strId = dataData;
201 bleCommandState = FIRMWARE_DOWNLOAD__EEPROM_READ_ID_DONE;
202 [self bleCommandTask];
203 } else if([dataType isEqualToString:@"infoDeviceModel"]) {
204 NSLog(@"infoDeviceModel");
205 strModel = dataData;
206 bleCommandState = FIRMWARE_DOWNLOAD__EEPROM_READ_MODEL_DONE;
207 [self bleCommandTask];
208 } else if([dataType isEqualToString:@"infoDeviceType"]) {
209 NSLog(@"infoDeviceType");
210 strType = dataData;
211 bleCommandState = FIRMWARE_DOWNLOAD__EEPROM_READ_TYPE_DONE;
212 [self bleCommandTask];
213 } else if([dataType isEqualToString:@"infoDeviceOs"]) {
214 NSLog(@"infoDeviceOs");
215 strOs = dataData;
216 bleCommandState = FIRMWARE_DOWNLOAD__EEPROM_READ_OS_DONE;
217 [self bleCommandTask];
218 }
219 }
220
221 /*
222 #pragma mark - Navigation
223
224 // In a storyboard-based application, you will often want to do a little preparation before navigation
225 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
226 // Get the new view controller using [segue destinationViewController].
227 // Pass the selected object to the new view controller.
228 }
229 */
230
231 @end
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
3 <device id="retina4_7" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
8 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9 </dependencies>
10 <objects>
11 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="FirmwareDownloadController">
12 <connections>
13 <outlet property="lblPercentComplete" destination="Mjh-27-eGB" id="13E-30-jj7"/>
14 <outlet property="tblFirmware" destination="erf-sK-RX7" id="tcE-GL-fEf"/>
15 <outlet property="view" destination="xbi-n3-MOM" id="qjE-58-VqO"/>
16 </connections>
17 </placeholder>
18 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
19 <view contentMode="scaleToFill" id="xbi-n3-MOM">
20 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
21 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
22 <subviews>
23 <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="erf-sK-RX7">
24 <rect key="frame" x="0.0" y="114" width="375" height="553"/>
25 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
26 </tableView>
27 <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Oce-KB-tk0">
28 <rect key="frame" x="0.0" y="23" width="375" height="44"/>
29 <items>
30 <navigationItem title="ファームウェアDL" id="iQA-Ru-iNE">
31 <barButtonItem key="leftBarButtonItem" title="戻る" id="feZ-vp-UB8">
32 <connections>
33 <action selector="cancelButtonClicked:" destination="-1" id="BbS-7p-KWV"/>
34 </connections>
35 </barButtonItem>
36 </navigationItem>
37 </items>
38 </navigationBar>
39 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Mjh-27-eGB">
40 <rect key="frame" x="0.0" y="85" width="375" height="21"/>
41 <constraints>
42 <constraint firstAttribute="height" constant="21" id="sgi-RD-ywG"/>
43 </constraints>
44 <fontDescription key="fontDescription" type="system" pointSize="17"/>
45 <nil key="textColor"/>
46 <nil key="highlightedColor"/>
47 </label>
48 </subviews>
49 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
50 <constraints>
51 <constraint firstItem="erf-sK-RX7" firstAttribute="trailing" secondItem="Mjh-27-eGB" secondAttribute="trailing" id="8cr-0D-Wsn"/>
52 <constraint firstItem="Mjh-27-eGB" firstAttribute="top" secondItem="Oce-KB-tk0" secondAttribute="bottom" constant="18" id="ChU-4v-QTf"/>
53 <constraint firstItem="erf-sK-RX7" firstAttribute="top" secondItem="Mjh-27-eGB" secondAttribute="bottom" constant="8" symbolic="YES" id="F4t-w2-3Ki"/>
54 <constraint firstItem="erf-sK-RX7" firstAttribute="leading" secondItem="Mjh-27-eGB" secondAttribute="leading" id="JEl-P9-VO6"/>
55 <constraint firstAttribute="trailing" secondItem="erf-sK-RX7" secondAttribute="trailing" id="KGd-4x-ijs"/>
56 <constraint firstAttribute="bottom" secondItem="erf-sK-RX7" secondAttribute="bottom" id="Kyb-Se-oRR"/>
57 <constraint firstItem="Oce-KB-tk0" firstAttribute="top" secondItem="xbi-n3-MOM" secondAttribute="top" constant="23" id="WZ0-1l-eIW"/>
58 <constraint firstItem="Oce-KB-tk0" firstAttribute="trailing" secondItem="Mjh-27-eGB" secondAttribute="trailing" id="bVM-cw-kfp"/>
59 <constraint firstItem="erf-sK-RX7" firstAttribute="leading" secondItem="xbi-n3-MOM" secondAttribute="leading" id="fXw-QY-PLy"/>
60 <constraint firstItem="Oce-KB-tk0" firstAttribute="leading" secondItem="Mjh-27-eGB" secondAttribute="leading" id="zmz-jd-CrP"/>
61 </constraints>
62 <point key="canvasLocation" x="-203.5" y="147.5"/>
63 </view>
64 </objects>
65 </document>
1 //
2 // FirmwareDownloadControllerTableViewCell.h
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/06/06.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10
11 @interface FirmwareDownloadControllerTableViewCell : UITableViewCell
12
13 @property (strong, nonatomic) IBOutlet UILabel *lblTitle;
14 @property (strong, nonatomic) IBOutlet UILabel *lblSubtitle;
15
16 @end
1 //
2 // FirmwareDownloadControllerTableCellTableViewCell.m
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/06/06.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "FirmwareDownloadControllerTableViewCell.h"
10
11 @implementation FirmwareDownloadControllerTableViewCell
12
13 - (void)awakeFromNib {
14 [super awakeFromNib];
15 // Initialization code
16 }
17
18 - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
19 [super setSelected:selected animated:animated];
20
21 // Configure the view for the selected state
22 }
23
24 @end
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
3 <device id="retina4_7" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
8 <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
9 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10 </dependencies>
11 <objects>
12 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
13 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
14 <tableViewCell contentMode="scaleToFill" restorationIdentifier="mycell" selectionStyle="default" indentationWidth="10" id="KGk-i7-Jjw" userLabel="Firmware Download Controller Table View Cell" customClass="FirmwareDownloadControllerTableViewCell">
15 <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
16 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
17 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
18 <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
19 <autoresizingMask key="autoresizingMask"/>
20 <subviews>
21 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="サブタイトル" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FUj-Q3-Rtz">
22 <rect key="frame" x="17" y="22" width="303" height="21"/>
23 <fontDescription key="fontDescription" type="system" pointSize="12"/>
24 <nil key="textColor"/>
25 <nil key="highlightedColor"/>
26 </label>
27 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="タイトル" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mMs-ai-Esq">
28 <rect key="frame" x="17" y="4" width="303" height="21"/>
29 <fontDescription key="fontDescription" type="system" pointSize="17"/>
30 <nil key="textColor"/>
31 <nil key="highlightedColor"/>
32 </label>
33 </subviews>
34 <constraints>
35 <constraint firstItem="FUj-Q3-Rtz" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" constant="14" id="Ifu-3l-cZ2"/>
36 <constraint firstItem="FUj-Q3-Rtz" firstAttribute="leading" secondItem="mMs-ai-Esq" secondAttribute="leading" id="OZM-Dl-ddG"/>
37 <constraint firstItem="mMs-ai-Esq" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" constant="-4" id="bey-do-AaT"/>
38 <constraint firstAttribute="bottomMargin" secondItem="FUj-Q3-Rtz" secondAttribute="bottom" constant="-7.5" id="hL8-P8-yuW"/>
39 <constraint firstItem="mMs-ai-Esq" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="9" id="kHc-HS-oAw"/>
40 <constraint firstItem="FUj-Q3-Rtz" firstAttribute="trailing" secondItem="mMs-ai-Esq" secondAttribute="trailing" id="sWv-je-ezI"/>
41 <constraint firstAttribute="trailing" secondItem="mMs-ai-Esq" secondAttribute="trailing" id="tab-yq-GfI"/>
42 </constraints>
43 </tableViewCellContentView>
44 <connections>
45 <outlet property="lblSubtitle" destination="FUj-Q3-Rtz" id="y7i-UH-MNh"/>
46 <outlet property="lblTitle" destination="mMs-ai-Esq" id="ODY-6M-Ul5"/>
47 </connections>
48 </tableViewCell>
49 </objects>
50 </document>
1 //
2 // FirmwareUpdateController.h
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/06/05.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10 #import "BleProtocol.h"
11 #import "BLE.h"
12
13 typedef enum {
14 MODE_FIRMWARE_IMAGE_SELECT_0_EEPROM_WP_OFF,
15 MODE_FIRMWARE_IMAGE_SELECT_0_EEPROM_WP_OFF_DONE,
16 MODE_FIRMWARE_IMAGE_SELECT_0_RESET_IN_BOOTLOADER,
17 MODE_FIRMWARE_IMAGE_SELECT_1_EEPROM_WP_OFF,
18 MODE_FIRMWARE_IMAGE_SELECT_1_EEPROM_WP_OFF_DONE,
19 MODE_FIRMWARE_IMAGE_SELECT_1,
20 MODE_FIRMWARE_IMAGE_SELECT_1_DONE,
21 MODE_FIRMWARE_IMAGE_SELECT_1_RESET,
22 } ModeFirmwareUpdateState;
23
24 @interface FirmwareUpdateController : UIViewController <BLEProtocolDelegate> {
25 ModeFirmwareUpdateState firmwareUpdateState;
26 }
27
28 @property (strong, nonatomic) IBOutlet UILabel *lblStateDownload;
29 @property (strong, nonatomic) IBOutlet UILabel *lblStateMCUWrite;
30
31 @property (strong, nonatomic) BleProtocol *protocol;
32 @property (nonatomic,assign) id <BLEProtocolDelegate> lastProtocolDelegate;
33
34 @end
1 //
2 // FirmwareUpdateController.m
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/06/05.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "FirmwareUpdateController.h"
10 #import "FirmwareWriteController.h"
11
12 @interface FirmwareUpdateController ()
13
14 @end
15
16 @implementation FirmwareUpdateController
17
18 - (void)viewDidLoad {
19 [super viewDidLoad];
20 // Do any additional setup after loading the view.
21 }
22
23 - (void)viewWillAppear:(BOOL)animated {
24 self.lastProtocolDelegate = self.protocol.delegate;
25 self.protocol.delegate = self;
26 }
27
28 - (void)viewWillDisappear:(BOOL)animated {
29 self.protocol.delegate = self.lastProtocolDelegate;
30 }
31
32 - (void)didReceiveMemoryWarning {
33 [super didReceiveMemoryWarning];
34 // Dispose of any resources that can be recreated.
35 }
36
37 /*
38 #pragma mark - Navigation
39
40 // In a storyboard-based application, you will often want to do a little preparation before navigation
41 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
42 // Get the new view controller using [segue destinationViewController].
43 // Pass the selected object to the new view controller.
44 }
45 */
46
47 - (IBAction)modeBootloaderButtonClicked:(id)sender {
48 firmwareUpdateState = MODE_FIRMWARE_IMAGE_SELECT_0_EEPROM_WP_OFF;
49 [self firmwareWriteTask];
50 }
51
52 - (IBAction)modeImage1ButtonClicked:(id)sender {
53 firmwareUpdateState = MODE_FIRMWARE_IMAGE_SELECT_1_EEPROM_WP_OFF;
54 [self firmwareWriteTask];
55 }
56
57 - (IBAction)cancelButtonClicked:(id)sender {
58 [self dismissViewControllerAnimated:YES completion:Nil];
59 }
60
61 - (IBAction)mcuWriteButtonClicked:(id)sender {
62 FirmwareWriteController *viewObj=[[FirmwareWriteController alloc] initWithNibName:@"FirmwareWriteController" bundle:nil];
63 viewObj.protocol = self.protocol;
64 [self presentViewController:viewObj animated:YES completion: nil];
65 }
66
67 - (void)protocolDidGetData:(NSString *)dataType data:(NSString *)dataData {
68 if([dataType isEqualToString:@"firmwareImageSelect"]) {
69 if([dataData isEqualToString: @"0"]) {
70 [[self protocol]putData:@"systemReset" data:nil];
71 } else if([dataData isEqualToString: @"1"]) {
72 [[self protocol]putData:@"systemReset" data:nil];
73 }
74 } else if([dataType isEqualToString:@"eepromWriteProtect"]) {
75 if([dataData isEqualToString:@"0"]) {
76 NSLog(@"firmwareImageSelect 0");
77 switch(firmwareUpdateState) {
78 case MODE_FIRMWARE_IMAGE_SELECT_0_EEPROM_WP_OFF:
79 firmwareUpdateState = MODE_FIRMWARE_IMAGE_SELECT_0_EEPROM_WP_OFF_DONE;
80 break;
81 case MODE_FIRMWARE_IMAGE_SELECT_1_EEPROM_WP_OFF:
82 firmwareUpdateState = MODE_FIRMWARE_IMAGE_SELECT_1_EEPROM_WP_OFF_DONE;
83 break;
84 default:
85 break;
86 }
87 [self firmwareWriteTask];
88 }
89 }
90 }
91
92 - (void)firmwareWriteTask {
93 switch(firmwareUpdateState) {
94 case MODE_FIRMWARE_IMAGE_SELECT_0_EEPROM_WP_OFF:
95 [[self protocol]putData:@"eepromWriteProtect" data:@"0"];
96 break;
97 case MODE_FIRMWARE_IMAGE_SELECT_0_EEPROM_WP_OFF_DONE:
98 firmwareUpdateState = MODE_FIRMWARE_IMAGE_SELECT_0_RESET_IN_BOOTLOADER;
99 [self firmwareWriteTask];
100 break;
101 case MODE_FIRMWARE_IMAGE_SELECT_0_RESET_IN_BOOTLOADER:
102 [[self protocol]putData:@"systemResetInBootloader" data:nil];
103 break;
104 case MODE_FIRMWARE_IMAGE_SELECT_1_EEPROM_WP_OFF:
105 [[self protocol]putData:@"eepromWriteProtect" data:@"0"];
106 break;
107 case MODE_FIRMWARE_IMAGE_SELECT_1_EEPROM_WP_OFF_DONE:
108 firmwareUpdateState = MODE_FIRMWARE_IMAGE_SELECT_1;
109 [self firmwareWriteTask];
110 break;
111 case MODE_FIRMWARE_IMAGE_SELECT_1:
112 [[self protocol]putData:@"firmwareImageSelect" data:@"1"];
113 break;
114 case MODE_FIRMWARE_IMAGE_SELECT_1_DONE:
115 firmwareUpdateState = MODE_FIRMWARE_IMAGE_SELECT_1_RESET;
116 [self firmwareWriteTask];
117 break;
118 case MODE_FIRMWARE_IMAGE_SELECT_1_RESET:
119 [[self protocol]putData:@"systemReset" data:nil];
120 break;
121 }
122 }
123
124 @end
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
3 <device id="retina4_7" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <deployment identifier="iOS"/>
8 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
9 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10 </dependencies>
11 <objects>
12 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="FirmwareUpdateController">
13 <connections>
14 <outlet property="lblStateMCUWrite" destination="4iS-Ml-6zs" id="O5y-do-L3o"/>
15 <outlet property="view" destination="Dee-Uj-9dH" id="pHd-FJ-YjS"/>
16 </connections>
17 </placeholder>
18 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
19 <view contentMode="scaleToFill" id="Dee-Uj-9dH">
20 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
21 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
22 <subviews>
23 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FCe-34-Low">
24 <rect key="frame" x="118" y="165" width="138" height="30"/>
25 <state key="normal" title="選択して書込み開始"/>
26 <connections>
27 <action selector="mcuWriteButtonClicked:" destination="-1" eventType="touchUpInside" id="mav-u1-ZQe"/>
28 </connections>
29 </button>
30 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="書き込み:なし" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4iS-Ml-6zs">
31 <rect key="frame" x="126" y="111" width="122" height="21"/>
32 <fontDescription key="fontDescription" type="system" pointSize="17"/>
33 <nil key="textColor"/>
34 <nil key="highlightedColor"/>
35 </label>
36 <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SZv-OE-aWd">
37 <rect key="frame" x="0.0" y="23" width="375" height="44"/>
38 <items>
39 <navigationItem title="ファームウェア更新" id="uhQ-pe-SM8">
40 <barButtonItem key="leftBarButtonItem" title="戻る" id="48U-xg-bRO">
41 <connections>
42 <action selector="cancelButtonClicked:" destination="-1" id="fys-Tk-uSB"/>
43 </connections>
44 </barButtonItem>
45 </navigationItem>
46 </items>
47 </navigationBar>
48 </subviews>
49 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
50 <constraints>
51 <constraint firstItem="4iS-Ml-6zs" firstAttribute="top" secondItem="SZv-OE-aWd" secondAttribute="bottom" constant="44" id="8bo-uQ-mYp"/>
52 <constraint firstItem="FCe-34-Low" firstAttribute="top" secondItem="4iS-Ml-6zs" secondAttribute="bottom" constant="33" id="9dJ-NV-aIu"/>
53 <constraint firstItem="4iS-Ml-6zs" firstAttribute="centerX" secondItem="FCe-34-Low" secondAttribute="centerX" id="Lt9-oI-Js3"/>
54 <constraint firstAttribute="trailing" secondItem="SZv-OE-aWd" secondAttribute="trailing" id="PHa-jh-RdD"/>
55 <constraint firstItem="4iS-Ml-6zs" firstAttribute="centerX" secondItem="SZv-OE-aWd" secondAttribute="centerX" id="ZFH-JH-KIM"/>
56 <constraint firstItem="SZv-OE-aWd" firstAttribute="top" secondItem="Dee-Uj-9dH" secondAttribute="top" constant="23" id="ak4-yS-Orr"/>
57 <constraint firstItem="SZv-OE-aWd" firstAttribute="leading" secondItem="Dee-Uj-9dH" secondAttribute="leading" id="nZt-Jg-g8l"/>
58 </constraints>
59 <point key="canvasLocation" x="21.5" y="-37.5"/>
60 </view>
61 </objects>
62 </document>
1 //
2 // FirmwareWriteController.h
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/06/06.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10 #import "BleProtocol.h"
11 #import "BLE.h"
12 #import <QuartzCore/QuartzCore.h>
13
14 typedef enum {
15 ERASE_PAGE_1,
16 UPLOAD_PAGE_10_ERASE_TEMP,
17 UPLOAD_PAGE_10_BEGIN,
18 UPLOAD_PAGE_10_CONTINUE,
19 UPLOAD_PAGE_10_RETRY,
20 UPLOAD_PAGE_10_END,
21 WRITE_PAGE_10,
22 WRITE_PAGE_10_DONE,
23 UPLOAD_PAGE_11_ERASE_TEMP,
24 UPLOAD_PAGE_11_BEGIN,
25 UPLOAD_PAGE_11_CONTINUE,
26 UPLOAD_PAGE_11_RETRY,
27 UPLOAD_PAGE_11_END,
28 WRITE_PAGE_11,
29 WRITE_PAGE_11_DONE,
30 UPLOAD_PAGE_12_ERASE_TEMP,
31 UPLOAD_PAGE_12_BEGIN,
32 UPLOAD_PAGE_12_CONTINUE,
33 UPLOAD_PAGE_12_RETRY,
34 UPLOAD_PAGE_12_END,
35 WRITE_PAGE_12,
36 WRITE_PAGE_12_DONE,
37 UPLOAD_PAGE_13_ERASE_TEMP,
38 UPLOAD_PAGE_13_BEGIN,
39 UPLOAD_PAGE_13_CONTINUE,
40 UPLOAD_PAGE_13_RETRY,
41 UPLOAD_PAGE_13_END,
42 WRITE_PAGE_13,
43 WRITE_PAGE_13_DONE,
44 UPLOAD_DONE,
45 EEPROM_WP_OFF,
46 EEPROM_WP_OFF_DONE,
47 FIRMWARE_IMAGE_SELECT_1,
48 FIRMWARE_IMAGE_SELECT_1_DONE,
49 RESET,
50 RESET_DONE
51 } FirmwareUpdateState;
52
53 @interface FirmwareWriteController : UIViewController<UITableViewDelegate, UITableViewDataSource, BLEProtocolDelegate> {
54
55 IBOutlet UITableView *tblFirmware;
56 IBOutlet UILabel *lblPercentComplete;
57 NSMutableArray *arrResult;
58 int selectionEnabled;
59 NSInputStream *firmwareFileStream;
60 unsigned long long firmwareFileStreamSize;
61 unsigned long long firmwareFileStreamPointer;
62 NSData *firmwareWriteBuffer;
63 int firmwareWriteBufferRetry;
64 FirmwareUpdateState firmwareUpdateState;
65 unsigned long long firmwareFlashPagePointer;
66 CFTimeInterval startTime;
67 }
68
69 @property (strong, nonatomic) BleProtocol *protocol;
70 @property (nonatomic,assign) id <BLEProtocolDelegate> lastProtocolDelegate;
71
72 - (BOOL)firmwareWriteTask;
73
74 @end
1 //
2 // FirmwareWriteController.m
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/06/06.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "FirmwareWriteController.h"
10 #import "FirmwareWriteControllerTableViewCell.h"
11 #import "Operation.h"
12 #import "DBManager.h"
13 #import "NSData+NSString.h"
14
15 @interface FirmwareWriteController ()
16
17 @end
18
19 @implementation FirmwareWriteController
20
21 - (void)viewDidLoad {
22 [super viewDidLoad];
23 // Do any additional setup after loading the view from its nib.
24
25 selectionEnabled = 1;
26
27 arrResult = [[NSMutableArray alloc] init];
28
29 UINib *nib = [UINib nibWithNibName:@"FirmwareWriteControllerTableViewCell" bundle:nil];
30 [tblFirmware registerNib:nib forCellReuseIdentifier:@"mycell"];
31 tblFirmware.delegate = self;
32 tblFirmware.dataSource = self;
33
34 [arrResult removeAllObjects];
35
36 NSArray *result = [[DBManager sharedInstance] getFirmwareDataList];
37
38 for(id key in result) {
39 NSString *valueId = [key objectAtIndex:0];
40 NSString *valueUuid = [key objectAtIndex:1];
41 NSString *valueDeviceType = [key objectAtIndex:2];
42 NSString *valueDeviceModel = [key objectAtIndex:3];
43 NSString *valueVersion = [key objectAtIndex:4];
44 NSString *valueVersionStamp = [key objectAtIndex:5];
45 NSString *valueFile = [key objectAtIndex:6];
46
47 NSMutableDictionary *newDict = [NSMutableDictionary dictionary];
48 [newDict setObject:valueId forKey:@"id"];
49 [newDict setObject:valueUuid forKey:@"uuid"];
50 [newDict setObject:valueDeviceType forKey:@"deviceType"];
51 [newDict setObject:valueDeviceModel forKey:@"deviceModel"];
52 [newDict setObject:valueVersion forKey:@"version"];
53 [newDict setObject:valueVersionStamp forKey:@"versionStamp"];
54 [newDict setObject:valueFile forKey:@"file"];
55
56 [arrResult addObject:newDict];
57 }
58 [tblFirmware reloadData];
59 }
60
61 - (void)viewWillAppear:(BOOL)animated {
62 self.lastProtocolDelegate = self.protocol.delegate;
63 self.protocol.delegate = self;
64 }
65
66 - (void)viewWillDisappear:(BOOL)animated {
67 self.protocol.delegate = self.lastProtocolDelegate;
68 }
69
70 - (void)didReceiveMemoryWarning {
71 [super didReceiveMemoryWarning];
72 // Dispose of any resources that can be recreated.
73 }
74
75 - (IBAction)cancelButtonClicked:(id)sender {
76 [self dismissViewControllerAnimated:YES completion:Nil];
77 }
78
79 - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
80 if(selectionEnabled == 1) {
81 return indexPath;
82 } else {
83 return nil;
84 }
85 }
86
87 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
88 NSInteger row = [indexPath row];
89 NSDictionary *dataRecord = [arrResult objectAtIndex:row];
90
91 NSString *filename = [dataRecord valueForKey:@"uuid"];
92
93 //selectionEnabled = 0;
94
95 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
96 NSUserDomainMask, YES);
97 NSString *documentsDirectory = [paths objectAtIndex:0];
98 NSString* path = [documentsDirectory stringByAppendingPathComponent:
99 [NSString stringWithFormat: @"/save/%@",filename]];
100 firmwareFileStreamSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil] fileSize];
101 firmwareFileStream = [[NSInputStream alloc] initWithFileAtPath:path];
102 [firmwareFileStream open];
103
104 startTime = CACurrentMediaTime();
105 firmwareUpdateState = ERASE_PAGE_1;
106 //firmwareUpdateState = UPLOAD_DONE;
107 firmwareFileStreamPointer = 0;
108 firmwareWriteBufferRetry = 0;
109
110 [self firmwareWriteTask];
111
112 NSLog(@"bin file readout complete");
113 }
114
115 - (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
116 {
117 return @[
118 [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive
119 title:@"削除"
120 handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
121 // own delete action
122
123
124 // Distructive button tapped.
125 NSLog(@"削除の確認");
126
127 NSDictionary * selectedData = [arrResult objectAtIndex:indexPath.row];
128 NSString *firmwareTitle = [selectedData valueForKey:@"file"];
129
130 UIAlertController *actionSheetConfirm = [UIAlertController alertControllerWithTitle:@"削除の確認" message:[NSString stringWithFormat:@"「%@」を削除します。よろしいですか?",firmwareTitle] preferredStyle:UIAlertControllerStyleAlert];
131
132 [actionSheetConfirm addAction:[UIAlertAction actionWithTitle:@"削除" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *actionConfirm) {
133
134
135 // Get the record ID of the selected name and set it to the recordIDToEdit property.
136 NSDictionary * selectedData = [arrResult objectAtIndex:indexPath.row];
137
138 NSString *recordId = [selectedData valueForKey:@"id"];
139 NSLog(@"recordId = %@",recordId);
140 //NSString *firmwareFilename = [selectedData valueForKey:@"file"];
141 NSString *firmwareFilename = [selectedData valueForKey:@"uuid"];
142 NSLog(@"firmwareFilename = %@",firmwareFilename);
143
144
145 NSString *docPath = [NSSearchPathForDirectoriesInDomains
146 (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
147 NSString *docPathFull = [docPath stringByAppendingPathComponent:[NSString stringWithFormat:@"/save/%@",firmwareFilename]];
148 //NSURL *docPathFullUrl = [NSURL URLWithString:docPathFull];
149
150
151 NSFileManager *fileManager = [NSFileManager defaultManager];
152 NSError *error;
153 BOOL success = [fileManager removeItemAtPath:docPathFull error:&error];
154 if(success) {
155 NSLog(@"削除した");
156 [[DBManager sharedInstance] deleteFirmwareData:recordId];
157 //[self populateDetail];
158 //[self.tblResult reloadData];
159 [arrResult removeObjectAtIndex:indexPath.row];
160 [tblFirmware deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
161 } else {
162 NSLog(@"削除を失敗した");
163 [[DBManager sharedInstance] deleteFirmwareData:recordId];
164 //[self populateDetail];
165 //[self.tblResult reloadData];
166 [arrResult removeObjectAtIndex:indexPath.row];
167 [tblFirmware deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
168 }
169 }]];
170 [actionSheetConfirm addAction:[UIAlertAction actionWithTitle:@"キャンセル" style:UIAlertActionStyleDefault handler:^(UIAlertAction *actionConfirm) {
171 // Distructive button tapped.
172 NSLog(@"キャンセルの確認");
173 }]];
174 [self presentViewController:actionSheetConfirm animated:YES completion:nil];
175 }],
176 ];
177 }
178
179 - (BOOL)firmwareWriteTask {
180 int packetDataSize = 18;
181 int readLength = 18;
182 unsigned long long firmwareFlashPageSize = 0x8000;
183 //unsigned long long firmwareFlashPageSize = 0x100;
184
185 switch(firmwareUpdateState) {
186 case ERASE_PAGE_1:
187 [[self protocol]putData:@"firmwareFlashErase" data:@"1"];
188 break;
189 case UPLOAD_PAGE_10_ERASE_TEMP:
190 [[self protocol]putData:@"firmwareBufferClear" data:nil];
191 break;
192 case UPLOAD_PAGE_10_BEGIN:
193 case UPLOAD_PAGE_11_BEGIN:
194 case UPLOAD_PAGE_12_BEGIN:
195 case UPLOAD_PAGE_13_BEGIN:
196 firmwareFlashPagePointer = firmwareFlashPageSize;
197 switch(firmwareUpdateState) {
198 case UPLOAD_PAGE_10_BEGIN:
199 firmwareUpdateState = UPLOAD_PAGE_10_CONTINUE;
200 break;
201 case UPLOAD_PAGE_11_BEGIN:
202 firmwareUpdateState = UPLOAD_PAGE_11_CONTINUE;
203 break;
204 case UPLOAD_PAGE_12_BEGIN:
205 firmwareUpdateState = UPLOAD_PAGE_12_CONTINUE;
206 break;
207 case UPLOAD_PAGE_13_BEGIN:
208 firmwareUpdateState = UPLOAD_PAGE_13_CONTINUE;
209 break;
210 default:
211 break;
212 }
213 case UPLOAD_PAGE_10_CONTINUE:
214 case UPLOAD_PAGE_11_CONTINUE:
215 case UPLOAD_PAGE_12_CONTINUE:
216 case UPLOAD_PAGE_13_CONTINUE:
217 {
218 if([firmwareFileStream hasBytesAvailable]) {
219 switch(firmwareUpdateState) {
220 case UPLOAD_PAGE_10_CONTINUE:
221 if((firmwareFileStreamPointer + readLength) > (firmwareFlashPageSize - 1)) {
222 readLength = (int)(firmwareFlashPageSize - firmwareFileStreamPointer);
223 }
224 break;
225 case UPLOAD_PAGE_11_CONTINUE:
226 if((firmwareFileStreamPointer + readLength) > (firmwareFlashPageSize * 2 - 1)) {
227 readLength = (int)(firmwareFlashPageSize * 2 - firmwareFileStreamPointer);
228 }
229 break;
230 case UPLOAD_PAGE_12_CONTINUE:
231 if((firmwareFileStreamPointer + readLength) > (firmwareFlashPageSize * 3 - 1)) {
232 readLength = (int)(firmwareFlashPageSize * 3 - firmwareFileStreamPointer);
233 }
234 break;
235 case UPLOAD_PAGE_13_CONTINUE:
236 if((firmwareFileStreamPointer + readLength) > (firmwareFlashPageSize * 4 - 1)) {
237 readLength = (int)(firmwareFlashPageSize * 4 - firmwareFileStreamPointer);
238 }
239 break;
240 default:
241 break;
242 }
243 unsigned char outputBuffer[20];
244 unsigned char outputBufferData[20];
245 for(int i = 0; i < 20; i++) {
246 outputBuffer[i] = 0;
247 outputBufferData[i] = 0;
248 }
249 NSInteger length = [firmwareFileStream read:outputBufferData maxLength:readLength];
250 firmwareFileStreamPointer += length;
251 firmwareFlashPagePointer -= length;
252
253
254 int indexFrom = 0;
255 int indexTo = 0;
256 outputBuffer[indexTo++] = 'x';
257 uint8_t outputBufferChecksum = 0x00;
258 while(indexFrom < length) {
259 outputBufferChecksum ^= outputBufferData[indexFrom];
260 outputBuffer[indexTo++] = outputBufferData[indexFrom++];
261 }
262 while(indexTo < (packetDataSize + 1)) {
263 outputBufferChecksum ^= 0xFF;
264 outputBuffer[indexTo++] = 0xFF;
265 }
266 outputBuffer[indexTo++] = outputBufferChecksum;
267
268 firmwareWriteBuffer = [NSData dataWithBytes:outputBuffer length:indexTo];
269
270 NSUInteger firmwareWriteBufferLength = [firmwareWriteBuffer length];
271 Byte *firmwareWriteBufferLengthByteData = (Byte*)malloc(firmwareWriteBufferLength);
272 memcpy(firmwareWriteBufferLengthByteData, [firmwareWriteBuffer bytes], firmwareWriteBufferLength);
273 NSMutableString *firmwareWriteBufferString = [NSMutableString stringWithCapacity:0];
274 for(int i = 0; i < [firmwareWriteBuffer length]; i++) {
275 [firmwareWriteBufferString appendFormat:@"%02x ", firmwareWriteBufferLengthByteData[i]];
276 }
277 CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
278 NSLog(@"BLE SEND(%d) %@ %llu / %llu %.2f%% %fsec",firmwareWriteBufferRetry,firmwareWriteBufferString,firmwareFileStreamPointer,firmwareFileStreamSize,(float)firmwareFileStreamPointer / (float)firmwareFileStreamSize * 100, elapsedTime);
279 lblPercentComplete.text = [NSString stringWithFormat:@"%llu / %llu %.2f%% %.02f秒",firmwareFileStreamPointer,firmwareFileStreamSize,(float)firmwareFileStreamPointer / (float)firmwareFileStreamSize * 100, elapsedTime];
280
281 [self.protocol bleWriteRaw:firmwareWriteBuffer];
282 } else if (firmwareFileStreamPointer == firmwareFileStreamSize) {
283 switch(firmwareUpdateState) {
284 case UPLOAD_PAGE_10_CONTINUE:
285 firmwareUpdateState = UPLOAD_PAGE_10_END;
286 break;
287 case UPLOAD_PAGE_11_CONTINUE:
288 firmwareUpdateState = UPLOAD_PAGE_11_END;
289 break;
290 case UPLOAD_PAGE_12_CONTINUE:
291 firmwareUpdateState = UPLOAD_PAGE_12_END;
292 break;
293 case UPLOAD_PAGE_13_CONTINUE:
294 firmwareUpdateState = UPLOAD_PAGE_13_END;
295 break;
296 default:
297 break;
298 }
299 [self firmwareWriteTask];
300 } else {
301 NSLog(@"Should not get here, something bad bad happened!!!");
302 NSLog(@"firmwareFileStreamPointer should never be larger than firmwareFileStreamSize, ever!!!");
303 }
304
305 //NSData *nsData = [@"fw@" dataUsingEncoding:NSUTF8StringEncoding];
306 //[self.protocol putData:@"infoDeviceId" data:nil];
307
308 return true;
309 break;
310 }
311 case UPLOAD_PAGE_10_RETRY:
312 case UPLOAD_PAGE_11_RETRY:
313 case UPLOAD_PAGE_12_RETRY:
314 case UPLOAD_PAGE_13_RETRY:
315 {
316 NSUInteger firmwareWriteBufferLength = [firmwareWriteBuffer length];
317
318 Byte *firmwareWriteBufferLengthByteData = (Byte*)malloc(firmwareWriteBufferLength);
319 memcpy(firmwareWriteBufferLengthByteData, [firmwareWriteBuffer bytes], firmwareWriteBufferLength);
320 NSMutableString *firmwareWriteBufferString = [NSMutableString stringWithCapacity:0];
321 for(int i = 0; i < [firmwareWriteBuffer length]; i++) {
322 [firmwareWriteBufferString appendFormat:@"%02x ", firmwareWriteBufferLengthByteData[i]];
323 }
324 CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
325 NSLog(@"BLE RESEND(%d) %@ %llu / %llu %.2f%% %fsec",firmwareWriteBufferRetry,firmwareWriteBufferString,firmwareFileStreamPointer,firmwareFileStreamSize,(float)firmwareFileStreamPointer / (float)firmwareFileStreamSize * 100, elapsedTime);
326 [self.protocol bleWriteRaw:firmwareWriteBuffer];
327
328 //NSData *nsData = [@"fw@" dataUsingEncoding:NSUTF8StringEncoding];
329 //[self.protocol putData:@"infoDeviceId" data:nil];
330
331 return true;
332 break;
333 }
334 case UPLOAD_PAGE_10_END:
335 firmwareUpdateState = WRITE_PAGE_10;
336 [self firmwareWriteTask];
337 break;
338 case WRITE_PAGE_10:
339 [[self protocol]putData:@"firmwareFlashWrite" data:@"10"];
340 break;
341 case WRITE_PAGE_10_DONE:
342 if (firmwareFileStreamPointer != firmwareFileStreamSize) {
343 firmwareUpdateState = UPLOAD_PAGE_11_ERASE_TEMP;
344 } else {
345 firmwareUpdateState = UPLOAD_DONE;
346 }
347 [self firmwareWriteTask];
348 break;
349 case UPLOAD_PAGE_11_ERASE_TEMP:
350 [[self protocol]putData:@"firmwareBufferClear" data:nil];
351 break;
352 case UPLOAD_PAGE_11_END:
353 firmwareUpdateState = WRITE_PAGE_11;
354 [self firmwareWriteTask];
355 break;
356 case WRITE_PAGE_11:
357 [[self protocol]putData:@"firmwareFlashWrite" data:@"11"];
358 break;
359 case WRITE_PAGE_11_DONE:
360 if (firmwareFileStreamPointer != firmwareFileStreamSize) {
361 firmwareUpdateState = UPLOAD_PAGE_12_ERASE_TEMP;
362 } else {
363 firmwareUpdateState = UPLOAD_DONE;
364 }
365 [self firmwareWriteTask];
366 break;
367 case UPLOAD_PAGE_12_ERASE_TEMP:
368 [[self protocol]putData:@"firmwareBufferClear" data:nil];
369 break;
370 case UPLOAD_PAGE_12_END:
371 firmwareUpdateState = WRITE_PAGE_12;
372 [self firmwareWriteTask];
373 break;
374 case WRITE_PAGE_12:
375 [[self protocol]putData:@"firmwareFlashWrite" data:@"12"];
376 break;
377 case WRITE_PAGE_12_DONE:
378 if (firmwareFileStreamPointer != firmwareFileStreamSize) {
379 firmwareUpdateState = UPLOAD_PAGE_13_ERASE_TEMP;
380 } else {
381 firmwareUpdateState = UPLOAD_DONE;
382 }
383 [self firmwareWriteTask];
384 break;
385 case UPLOAD_PAGE_13_ERASE_TEMP:
386 [[self protocol]putData:@"firmwareBufferClear" data:nil];
387 break;
388 case UPLOAD_PAGE_13_END:
389 firmwareUpdateState = WRITE_PAGE_13;
390 [self firmwareWriteTask];
391 break;
392 case WRITE_PAGE_13:
393 [[self protocol]putData:@"firmwareFlashWrite" data:@"13"];
394 break;
395 case WRITE_PAGE_13_DONE:
396 firmwareUpdateState = UPLOAD_DONE;
397 [self firmwareWriteTask];
398 break;
399 case UPLOAD_DONE:
400 //firmwareUpdateState = EEPROM_WP_OFF;
401 //[self firmwareWriteTask];
402 {
403 CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
404 NSLog(@"Firmware upload done! %fsec", elapsedTime);
405 break;
406 }
407 case EEPROM_WP_OFF:
408 [[self protocol]putData:@"eepromWriteProtect" data:@"0"];
409 break;
410 case EEPROM_WP_OFF_DONE:
411 firmwareUpdateState = FIRMWARE_IMAGE_SELECT_1;
412 [self firmwareWriteTask];
413 break;
414 case FIRMWARE_IMAGE_SELECT_1:
415 [[self protocol]putData:@"firmwareImageSelect" data:@"1"];
416 break;
417 case FIRMWARE_IMAGE_SELECT_1_DONE:
418 firmwareUpdateState = RESET;
419 [self firmwareWriteTask];
420 break;
421 case RESET:
422 [[self protocol]putData:@"systemReset" data:nil];
423 break;
424 case RESET_DONE:
425 {
426 CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
427 NSLog(@"Firmware upload done! %fsec", elapsedTime);
428 break;
429 }
430 }
431 return false;
432 }
433
434 - (void)protocolDidGetData:(NSString *)dataType data:(NSString *)dataData {
435 if([dataType isEqualToString:@"firmwareFlashErase"]) {
436 if([dataData isEqualToString: @"1"]) {
437 if(firmwareUpdateState == ERASE_PAGE_1) {
438 firmwareUpdateState = UPLOAD_PAGE_10_ERASE_TEMP;
439 [self firmwareWriteTask];
440 }
441 }
442 } else if([dataType isEqualToString:@"firmwareBufferClear"]) {
443 switch(firmwareUpdateState) {
444 case UPLOAD_PAGE_10_ERASE_TEMP:
445 firmwareUpdateState = UPLOAD_PAGE_10_BEGIN;
446 break;
447 case UPLOAD_PAGE_11_ERASE_TEMP:
448 firmwareUpdateState = UPLOAD_PAGE_11_BEGIN;
449 break;
450 case UPLOAD_PAGE_12_ERASE_TEMP:
451 firmwareUpdateState = UPLOAD_PAGE_12_BEGIN;
452 break;
453 case UPLOAD_PAGE_13_ERASE_TEMP:
454 firmwareUpdateState = UPLOAD_PAGE_13_BEGIN;
455 break;
456 default:
457 break;
458 }
459 [self firmwareWriteTask];
460 } else if([dataType isEqualToString:@"firmwareBufferWrite"]) {
461 if([dataData isEqualToString: @"OK"]) {
462 if(firmwareWriteBufferRetry != 0) {
463 firmwareWriteBufferRetry = 0;
464 switch(firmwareUpdateState) {
465 case UPLOAD_PAGE_10_RETRY:
466 firmwareUpdateState = UPLOAD_PAGE_10_CONTINUE;
467 break;
468 case UPLOAD_PAGE_11_RETRY:
469 firmwareUpdateState = UPLOAD_PAGE_11_CONTINUE;
470 break;
471 case UPLOAD_PAGE_12_RETRY:
472 firmwareUpdateState = UPLOAD_PAGE_12_CONTINUE;
473 break;
474 case UPLOAD_PAGE_13_RETRY:
475 firmwareUpdateState = UPLOAD_PAGE_13_CONTINUE;
476 break;
477 default:
478 break;
479 }
480 }
481 if(firmwareFlashPagePointer == 0) {
482 switch(firmwareUpdateState) {
483 case UPLOAD_PAGE_10_CONTINUE:
484 firmwareUpdateState = UPLOAD_PAGE_10_END;
485 break;
486 case UPLOAD_PAGE_11_CONTINUE:
487 firmwareUpdateState = UPLOAD_PAGE_11_END;
488 break;
489 case UPLOAD_PAGE_12_CONTINUE:
490 firmwareUpdateState = UPLOAD_PAGE_12_END;
491 break;
492 case UPLOAD_PAGE_13_CONTINUE:
493 firmwareUpdateState = UPLOAD_PAGE_13_END;
494 break;
495 default:
496 break;
497 }
498 }
499 [self firmwareWriteTask];
500 } else {
501 if(firmwareWriteBufferRetry < 10) {
502 firmwareWriteBufferRetry++;
503 switch(firmwareUpdateState) {
504 case UPLOAD_PAGE_10_CONTINUE:
505 firmwareUpdateState = UPLOAD_PAGE_10_RETRY;
506 break;
507 case UPLOAD_PAGE_11_CONTINUE:
508 firmwareUpdateState = UPLOAD_PAGE_11_RETRY;
509 break;
510 case UPLOAD_PAGE_12_CONTINUE:
511 firmwareUpdateState = UPLOAD_PAGE_12_RETRY;
512 break;
513 case UPLOAD_PAGE_13_CONTINUE:
514 firmwareUpdateState = UPLOAD_PAGE_13_RETRY;
515 break;
516 default:
517 break;
518 }
519 [self firmwareWriteTask];
520 } else {
521 NSLog(@"BLE RESEND(%d) RETRY EXCEED, GIVE UP",firmwareWriteBufferRetry);
522 }
523 }
524 } else if([dataType isEqualToString:@"firmwareFlashWrite"]) {
525 if([dataData isEqualToString:@"10"]) {
526 NSLog(@"firmwareFlashWrite 10");
527 firmwareUpdateState = WRITE_PAGE_10_DONE;
528 [self firmwareWriteTask];
529 } else if([dataData isEqualToString:@"11"]) {
530 NSLog(@"firmwareFlashWrite 11");
531 firmwareUpdateState = WRITE_PAGE_11_DONE;
532 [self firmwareWriteTask];
533 } else if([dataData isEqualToString:@"12"]) {
534 NSLog(@"firmwareFlashWrite 12");
535 firmwareUpdateState = WRITE_PAGE_12_DONE;
536 [self firmwareWriteTask];
537 } else if([dataData isEqualToString:@"13"]) {
538 NSLog(@"firmwareFlashWrite 13");
539 firmwareUpdateState = WRITE_PAGE_13_DONE;
540 [self firmwareWriteTask];
541 }
542 } else if([dataType isEqualToString:@"firmwareImageSelect"]) {
543 if([dataData isEqualToString:@"1"]) {
544 NSLog(@"firmwareImageSelect 1");
545 firmwareUpdateState = FIRMWARE_IMAGE_SELECT_1_DONE;
546 [self firmwareWriteTask];
547 }
548 } else if([dataType isEqualToString:@"eepromWriteProtect"]) {
549 if([dataData isEqualToString:@"0"]) {
550 NSLog(@"firmwareImageSelect 0");
551 firmwareUpdateState = EEPROM_WP_OFF_DONE;
552 [self firmwareWriteTask];
553 }
554 } else if([dataType isEqualToString:@"systemReset"]) {
555 NSLog(@"firmwareImageSelect 1");
556 firmwareUpdateState = RESET_DONE;
557 [self firmwareWriteTask];
558 }
559 }
560
561 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
562 // Return the number of sections.
563 return 1;
564 }
565
566 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
567 // Return the number of rows in the section.
568 return [arrResult count];
569 }
570
571 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
572 {
573 static NSString *cellIdentifier = @"mycell";
574 FirmwareWriteControllerTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
575
576 NSInteger row = [indexPath row];
577 NSDictionary *dataRecord = [arrResult objectAtIndex:row];
578
579 // Configure the cell...
580 UIFont *newFont = [UIFont fontWithName:@"Arial" size:11.0];
581 cell.lblTitle.font = newFont;
582 cell.lblTitle.text = [dataRecord valueForKey:@"file"];
583
584 newFont = [UIFont fontWithName:@"Arial" size:11.0];
585 cell.lblSubtitle.font = newFont;
586 cell.lblSubtitle.text = [dataRecord valueForKey:@"uuid"];
587
588 return cell;
589 }
590
591 /*
592 #pragma mark - Navigation
593
594 // In a storyboard-based application, you will often want to do a little preparation before navigation
595 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
596 // Get the new view controller using [segue destinationViewController].
597 // Pass the selected object to the new view controller.
598 }
599 */
600
601 @end
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
3 <device id="retina4_7" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
8 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9 </dependencies>
10 <objects>
11 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="FirmwareWriteController">
12 <connections>
13 <outlet property="lblPercentComplete" destination="gbe-O8-4MZ" id="tzg-Iq-QuD"/>
14 <outlet property="tblFirmware" destination="Bm4-3e-kcl" id="MoB-u5-JGI"/>
15 <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
16 </connections>
17 </placeholder>
18 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
19 <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
20 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
21 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
22 <subviews>
23 <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GD6-XB-ga1">
24 <rect key="frame" x="0.0" y="23" width="375" height="44"/>
25 <items>
26 <navigationItem title="ファームウェア書き込み" id="M6c-ur-fNv">
27 <barButtonItem key="leftBarButtonItem" title="戻る" id="vHb-pY-nI8">
28 <connections>
29 <action selector="cancelButtonClicked:" destination="-1" id="PP3-RL-PMI"/>
30 </connections>
31 </barButtonItem>
32 </navigationItem>
33 </items>
34 </navigationBar>
35 <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="Bm4-3e-kcl">
36 <rect key="frame" x="0.0" y="114" width="375" height="553"/>
37 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
38 </tableView>
39 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gbe-O8-4MZ">
40 <rect key="frame" x="0.0" y="85" width="375" height="21"/>
41 <constraints>
42 <constraint firstAttribute="height" constant="21" id="EGb-VE-YbS"/>
43 </constraints>
44 <fontDescription key="fontDescription" type="system" pointSize="17"/>
45 <nil key="textColor"/>
46 <nil key="highlightedColor"/>
47 </label>
48 </subviews>
49 <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
50 <constraints>
51 <constraint firstItem="Bm4-3e-kcl" firstAttribute="trailing" secondItem="gbe-O8-4MZ" secondAttribute="trailing" id="Abo-tT-Thu"/>
52 <constraint firstItem="GD6-XB-ga1" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="FtV-kf-WI3"/>
53 <constraint firstItem="gbe-O8-4MZ" firstAttribute="top" secondItem="GD6-XB-ga1" secondAttribute="bottom" constant="18" id="GoQ-Q5-91K"/>
54 <constraint firstItem="Bm4-3e-kcl" firstAttribute="top" secondItem="gbe-O8-4MZ" secondAttribute="bottom" constant="8" symbolic="YES" id="Une-zo-zte"/>
55 <constraint firstItem="gbe-O8-4MZ" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="fxk-Ov-pU5"/>
56 <constraint firstItem="Bm4-3e-kcl" firstAttribute="leading" secondItem="gbe-O8-4MZ" secondAttribute="leading" id="gbQ-tt-xdK"/>
57 <constraint firstAttribute="trailing" secondItem="GD6-XB-ga1" secondAttribute="trailing" id="jWA-Pb-qcK"/>
58 <constraint firstAttribute="trailing" secondItem="gbe-O8-4MZ" secondAttribute="trailing" id="qg6-AW-Ney"/>
59 <constraint firstAttribute="bottom" secondItem="Bm4-3e-kcl" secondAttribute="bottom" id="u5Z-t5-eje"/>
60 <constraint firstItem="GD6-XB-ga1" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="23" id="zUz-9r-bi8"/>
61 </constraints>
62 <point key="canvasLocation" x="24.5" y="52.5"/>
63 </view>
64 </objects>
65 </document>
1 //
2 // FirmwareWriteControllerTableViewCell.h
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/06/07.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10
11 @interface FirmwareWriteControllerTableViewCell : UITableViewCell
12
13 @property (strong, nonatomic) IBOutlet UILabel *lblTitle;
14 @property (strong, nonatomic) IBOutlet UILabel *lblSubtitle;
15
16 @end
1 //
2 // FirmwareWriteControllerTableViewCell.m
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/06/07.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "FirmwareWriteControllerTableViewCell.h"
10
11 @implementation FirmwareWriteControllerTableViewCell
12
13 - (void)awakeFromNib {
14 [super awakeFromNib];
15 // Initialization code
16 }
17
18 - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
19 [super setSelected:selected animated:animated];
20
21 // Configure the view for the selected state
22 }
23
24 @end
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
3 <device id="retina4_7" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
8 <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
9 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10 </dependencies>
11 <objects>
12 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
13 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
14 <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="KGk-i7-Jjw" customClass="FirmwareWriteControllerTableViewCell">
15 <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
16 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
17 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
18 <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
19 <autoresizingMask key="autoresizingMask"/>
20 <subviews>
21 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="タイトル" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hee-i7-oLg">
22 <rect key="frame" x="17" y="4" width="303" height="21"/>
23 <fontDescription key="fontDescription" type="system" pointSize="17"/>
24 <nil key="textColor"/>
25 <nil key="highlightedColor"/>
26 </label>
27 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="サブタイトル" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XEF-Tk-t7H">
28 <rect key="frame" x="17" y="22" width="303" height="21"/>
29 <fontDescription key="fontDescription" type="system" pointSize="12"/>
30 <nil key="textColor"/>
31 <nil key="highlightedColor"/>
32 </label>
33 </subviews>
34 <constraints>
35 <constraint firstItem="XEF-Tk-t7H" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" constant="14" id="4fz-2b-2iR"/>
36 <constraint firstAttribute="trailing" secondItem="hee-i7-oLg" secondAttribute="trailing" id="FPe-q7-Kt0"/>
37 <constraint firstItem="hee-i7-oLg" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="9" id="LWf-z4-6OC"/>
38 <constraint firstItem="hee-i7-oLg" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" constant="-4" id="aU2-zO-01S"/>
39 <constraint firstItem="hee-i7-oLg" firstAttribute="trailing" secondItem="XEF-Tk-t7H" secondAttribute="trailing" id="onp-HC-6zn"/>
40 <constraint firstItem="hee-i7-oLg" firstAttribute="leading" secondItem="XEF-Tk-t7H" secondAttribute="leading" id="wGx-O2-PWb"/>
41 <constraint firstAttribute="bottomMargin" secondItem="XEF-Tk-t7H" secondAttribute="bottom" constant="-7.5" id="yYM-VE-A2L"/>
42 </constraints>
43 </tableViewCellContentView>
44 <connections>
45 <outlet property="lblSubtitle" destination="XEF-Tk-t7H" id="6ub-Gh-yfi"/>
46 <outlet property="lblTitle" destination="hee-i7-oLg" id="Exz-fq-eqY"/>
47 </connections>
48 </tableViewCell>
49 </objects>
50 </document>
1 //
2 // InputMotorController.h
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/02/23.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10 #import "BleProtocol.h"
11 #import "BLE.h"
12
13 @interface InputMotorController : UIViewController <BLEProtocolDelegate>
14
15 @property (nonatomic, strong) NSString *jacketId;
16 @property (strong, nonatomic) BleProtocol *protocol;
17 @property (nonatomic,assign) id <BLEProtocolDelegate> lastProtocolDelegate;
18
19 @end
1 //
2 // InputMotorController.m
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/02/23.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "InputMotorController.h"
10
11 @interface InputMotorController ()
12 @property (strong, nonatomic) IBOutlet UIButton *btn0;
13 @property (strong, nonatomic) IBOutlet UIButton *btn1;
14 @property (strong, nonatomic) IBOutlet UIButton *btn2;
15
16 @end
17
18 @implementation InputMotorController {
19 UIView *_mask;
20 NSTimer *_writeResponseTimer;
21 bool ignoreWriteResponse;
22 id lastButton;
23 NSInteger newState;
24 }
25 @synthesize protocol;
26
27 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
28 [_mask removeFromSuperview];
29 [self dismissViewControllerAnimated:YES completion:Nil];
30 }
31
32 - (void)viewWillAppear:(BOOL)animated {
33 [super viewWillAppear:animated];
34 _lastProtocolDelegate = protocol.delegate;
35 protocol.delegate = self;
36 }
37
38 - (void)viewWillDisappear:(BOOL)animated {
39 [super viewWillDisappear:animated];
40 protocol.delegate = _lastProtocolDelegate;
41 }
42
43 - (void)viewDidLoad {
44 [super viewDidLoad];
45 // Do any additional setup after loading the view from its nib.
46 }
47
48 - (void)didReceiveMemoryWarning {
49 [super didReceiveMemoryWarning];
50 // Dispose of any resources that can be recreated.
51 }
52
53 /*
54 #pragma mark - Navigation
55
56 // In a storyboard-based application, you will often want to do a little preparation before navigation
57 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
58 // Get the new view controller using [segue destinationViewController].
59 // Pass the selected object to the new view controller.
60 }
61 */
62 - (void)showAlert {
63 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"ジャケットの設定"
64 message:@"設定が保存されました。"
65 delegate:self
66 cancelButtonTitle:@"OK"
67 otherButtonTitles:nil];
68 [alert show];
69 }
70
71 - (void)showAlert:(NSString*)title message:(NSString*)message{
72 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
73 message:message
74 delegate:self
75 cancelButtonTitle:@"OK"
76 otherButtonTitles:nil];
77 [alert show];
78 }
79
80 - (void)showMask {
81 _mask = [[UIView alloc] initWithFrame:[self.view frame]];
82 [_mask setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0.25]];
83 [self.view addSubview:_mask];
84 }
85
86 -(void)writeResponseTimeout:(NSTimer *)timer {
87 ignoreWriteResponse = true;
88 [self showAlert:@"ジャケットの設定" message:@"設定が保存されない。"];
89 }
90
91 - (void)protocolDidGetData:(NSString *)dataType data:(NSString *)dataData {
92 if([dataType isEqualToString:@"writeMotor"]){
93 if(ignoreWriteResponse) return;
94 [_writeResponseTimer invalidate];
95
96 if([dataData isEqual:@"OK"]) {
97 [self showAlert:@"ジャケットの設定" message:@"設定が保存されました。"];
98 } else {
99 [self showAlert:@"ジャケットの設定" message:@"設定が保存されない。"];
100 }
101 }
102 }
103
104 - (IBAction)btn0:(id)sender {
105 if(lastButton) {
106 [lastButton setBackgroundColor:[UIColor clearColor]];
107 }
108 lastButton = sender;
109 newState = 0;
110 [sender setBackgroundColor:[UIColor yellowColor]];
111 }
112
113 - (IBAction)btn1:(id)sender {
114 if(lastButton) {
115 [lastButton setBackgroundColor:[UIColor clearColor]];
116 }
117 lastButton = sender;
118 newState = 1;
119 [sender setBackgroundColor:[UIColor yellowColor]];
120 }
121
122 - (IBAction)btn2:(id)sender {
123 if(lastButton) {
124 [lastButton setBackgroundColor:[UIColor clearColor]];
125 }
126 lastButton = sender;
127 newState = 2;
128 [sender setBackgroundColor:[UIColor yellowColor]];
129 }
130
131 - (IBAction)cancelButtonClicked:(id)sender {
132 [self dismissViewControllerAnimated:YES completion:Nil];
133 }
134
135 - (IBAction)saveButtonClicked:(id)sender {
136 ignoreWriteResponse = false;
137 [self showMask];
138 [protocol putData:@"writeMotor" data:[NSString stringWithFormat:@"%ld",newState]];
139 _writeResponseTimer = [NSTimer scheduledTimerWithTimeInterval: 5.0 target: self selector:@selector(writeResponseTimeout:) userInfo: nil repeats:NO];
140 }
141
142 @end
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
3 <device id="retina4_7" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <deployment identifier="iOS"/>
8 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
9 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10 </dependencies>
11 <objects>
12 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="InputMotorController">
13 <connections>
14 <outlet property="btn0" destination="y6L-Z8-PBp" id="0If-yX-pUs"/>
15 <outlet property="btn1" destination="N8B-HG-KJu" id="Qjf-65-PYn"/>
16 <outlet property="btn2" destination="YiN-Ek-vti" id="Fng-yV-kXC"/>
17 <outlet property="view" destination="9aV-RW-OZ8" id="LHe-HA-LNf"/>
18 </connections>
19 </placeholder>
20 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
21 <view contentMode="scaleToFill" id="9aV-RW-OZ8">
22 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
23 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
24 <subviews>
25 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="y6L-Z8-PBp">
26 <rect key="frame" x="172" y="97" width="30" height="30"/>
27 <state key="normal" title="OFF"/>
28 <connections>
29 <action selector="btn0:" destination="-2" eventType="touchUpInside" id="ASw-mk-2I6"/>
30 <action selector="btn0:" destination="-1" eventType="touchUpInside" id="eTs-nj-jCz"/>
31 </connections>
32 </button>
33 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="N8B-HG-KJu">
34 <rect key="frame" x="89" y="157" width="197" height="30"/>
35 <state key="normal" title="ON 0 (iOSホームボタン押し)"/>
36 <connections>
37 <action selector="btn1:" destination="-2" eventType="touchUpInside" id="VWj-L6-FAy"/>
38 <action selector="btn1:" destination="-1" eventType="touchUpInside" id="i5s-rG-fdC"/>
39 </connections>
40 </button>
41 <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8X3-1K-oyZ">
42 <rect key="frame" x="0.0" y="23" width="375" height="44"/>
43 <items>
44 <navigationItem title="モーターの設定" id="JpB-f0-A8S">
45 <barButtonItem key="leftBarButtonItem" title="戻る" id="QfV-3b-uNb">
46 <connections>
47 <action selector="cancelButtonClicked:" destination="-1" id="kSA-tc-wgg"/>
48 </connections>
49 </barButtonItem>
50 <barButtonItem key="rightBarButtonItem" title="保存" id="Jvg-is-ZAy">
51 <connections>
52 <action selector="saveButtonClicked:" destination="-1" id="xkU-dg-36I"/>
53 </connections>
54 </barButtonItem>
55 </navigationItem>
56 </items>
57 </navigationBar>
58 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="YiN-Ek-vti">
59 <rect key="frame" x="61" y="217" width="253" height="30"/>
60 <state key="normal" title="ON 1(ANDRIODホームボタン押し)"/>
61 <connections>
62 <action selector="btn2:" destination="-1" eventType="touchUpInside" id="avV-Oc-oJQ"/>
63 <action selector="btn2:" destination="-2" eventType="touchUpInside" id="yzK-gg-Icl"/>
64 </connections>
65 </button>
66 </subviews>
67 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
68 <constraints>
69 <constraint firstItem="y6L-Z8-PBp" firstAttribute="top" secondItem="8X3-1K-oyZ" secondAttribute="bottom" constant="30" id="1IP-9d-ZtC"/>
70 <constraint firstItem="N8B-HG-KJu" firstAttribute="top" secondItem="y6L-Z8-PBp" secondAttribute="bottom" constant="30" id="ExD-uU-gJa"/>
71 <constraint firstItem="8X3-1K-oyZ" firstAttribute="centerX" secondItem="y6L-Z8-PBp" secondAttribute="centerX" id="JPi-Xc-I0P"/>
72 <constraint firstItem="YiN-Ek-vti" firstAttribute="top" secondItem="N8B-HG-KJu" secondAttribute="bottom" constant="30" id="O9g-kB-Qwr"/>
73 <constraint firstItem="y6L-Z8-PBp" firstAttribute="top" secondItem="8X3-1K-oyZ" secondAttribute="bottom" constant="30" id="ZmM-NH-pzR"/>
74 <constraint firstItem="N8B-HG-KJu" firstAttribute="centerX" secondItem="9aV-RW-OZ8" secondAttribute="centerX" id="apJ-QU-yP3"/>
75 <constraint firstItem="8X3-1K-oyZ" firstAttribute="top" secondItem="9aV-RW-OZ8" secondAttribute="top" constant="23" id="hqq-Uz-88D"/>
76 <constraint firstItem="YiN-Ek-vti" firstAttribute="centerX" secondItem="9aV-RW-OZ8" secondAttribute="centerX" id="kg8-xM-aVZ"/>
77 <constraint firstAttribute="trailing" secondItem="8X3-1K-oyZ" secondAttribute="trailing" id="lb2-Nl-Lmt"/>
78 <constraint firstItem="8X3-1K-oyZ" firstAttribute="leading" secondItem="9aV-RW-OZ8" secondAttribute="leading" id="xcc-yg-Zzi"/>
79 <constraint firstItem="y6L-Z8-PBp" firstAttribute="centerX" secondItem="9aV-RW-OZ8" secondAttribute="centerX" id="z3G-w1-vpt"/>
80 </constraints>
81 <point key="canvasLocation" x="-67" y="-73"/>
82 </view>
83 </objects>
84 </document>
1 //
2 // InputSoundController.h
3 // jacket_test_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/10/06.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10 #import "BleProtocol.h"
11 #import "BLE.h"
12
13 @interface InputSoundController : UIViewController <BLEProtocolDelegate>
14
15 @property (nonatomic, strong) NSString *jacketId;
16 @property (strong, nonatomic) BleProtocol *protocol;
17 @property (nonatomic,assign) id <BLEProtocolDelegate> lastProtocolDelegate;
18
19 @end
1 //
2 // InputSoundController.m
3 // jacket_test_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/10/06.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "InputSoundController.h"
10
11 @interface InputSoundController ()
12 @property (strong, nonatomic) IBOutlet UIButton *btn0;
13 @property (strong, nonatomic) IBOutlet UIButton *btn1;
14
15 @end
16
17 @implementation InputSoundController {
18 UIView *_mask;
19 NSTimer *_writeResponseTimer;
20 bool ignoreWriteResponse;
21 id lastButton;
22 NSInteger newState;
23 }
24 @synthesize protocol;
25
26 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
27 [_mask removeFromSuperview];
28 [self dismissViewControllerAnimated:YES completion:Nil];
29 }
30
31 - (void)viewWillAppear:(BOOL)animated {
32 [super viewWillAppear:animated];
33 _lastProtocolDelegate = protocol.delegate;
34 protocol.delegate = self;
35 }
36
37 - (void)viewWillDisappear:(BOOL)animated {
38 [super viewWillDisappear:animated];
39 protocol.delegate = _lastProtocolDelegate;
40 }
41
42 - (void)viewDidLoad {
43 [super viewDidLoad];
44 // Do any additional setup after loading the view from its nib.
45 }
46
47 - (void)didReceiveMemoryWarning {
48 [super didReceiveMemoryWarning];
49 // Dispose of any resources that can be recreated.
50 }
51
52 /*
53 #pragma mark - Navigation
54
55 // In a storyboard-based application, you will often want to do a little preparation before navigation
56 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
57 // Get the new view controller using [segue destinationViewController].
58 // Pass the selected object to the new view controller.
59 }
60 */
61 - (void)showAlert {
62 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"ジャケットの設定"
63 message:@"設定が保存されました。"
64 delegate:self
65 cancelButtonTitle:@"OK"
66 otherButtonTitles:nil];
67 [alert show];
68 }
69
70 - (void)showAlert:(NSString*)title message:(NSString*)message{
71 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
72 message:message
73 delegate:self
74 cancelButtonTitle:@"OK"
75 otherButtonTitles:nil];
76 [alert show];
77 }
78
79 - (void)showMask {
80 _mask = [[UIView alloc] initWithFrame:[self.view frame]];
81 [_mask setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0.25]];
82 [self.view addSubview:_mask];
83 }
84
85 -(void)writeResponseTimeout:(NSTimer *)timer {
86 ignoreWriteResponse = true;
87 [self showAlert:@"ジャケットの設定" message:@"設定が保存されない。"];
88 }
89
90 - (void)protocolDidGetData:(NSString *)dataType data:(NSString *)dataData {
91 if([dataType isEqualToString:@"writeSound"]){
92 if(ignoreWriteResponse) return;
93 [_writeResponseTimer invalidate];
94
95 if([dataData isEqual:@"OK"]) {
96 [self showAlert:@"ジャケットの設定" message:@"設定が保存されました。"];
97 } else {
98 [self showAlert:@"ジャケットの設定" message:@"設定が保存されない。"];
99 }
100 }
101 }
102
103 - (IBAction)btn0:(id)sender {
104 if(lastButton) {
105 [lastButton setBackgroundColor:[UIColor clearColor]];
106 }
107 lastButton = sender;
108 newState = 0;
109 [sender setBackgroundColor:[UIColor yellowColor]];
110 }
111
112 - (IBAction)btn1:(id)sender {
113 if(lastButton) {
114 [lastButton setBackgroundColor:[UIColor clearColor]];
115 }
116 lastButton = sender;
117 newState = 1;
118 [sender setBackgroundColor:[UIColor yellowColor]];
119 }
120
121 - (IBAction)cancelButtonClicked:(id)sender {
122 [self dismissViewControllerAnimated:YES completion:Nil];
123 }
124
125 - (IBAction)saveButtonClicked:(id)sender {
126 ignoreWriteResponse = false;
127 [self showMask];
128 [protocol putData:@"writeSound" data:[NSString stringWithFormat:@"%ld",newState]];
129 _writeResponseTimer = [NSTimer scheduledTimerWithTimeInterval: 5.0 target: self selector:@selector(writeResponseTimeout:) userInfo: nil repeats:NO];
130 }
131
132 @end
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3 <device id="retina4_7" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <deployment identifier="iOS"/>
8 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13173"/>
9 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10 </dependencies>
11 <objects>
12 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="InputSoundController">
13 <connections>
14 <outlet property="btn0" destination="PpR-jP-zBp" id="3vy-Dd-cfz"/>
15 <outlet property="btn1" destination="AoY-L8-av3" id="XJd-q4-Hsz"/>
16 <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
17 </connections>
18 </placeholder>
19 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
20 <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
21 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
22 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
23 <subviews>
24 <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="MGO-KK-hkK">
25 <rect key="frame" x="0.0" y="23" width="375" height="44"/>
26 <items>
27 <navigationItem title="サウンドの設定" id="3l5-OJ-hVk">
28 <barButtonItem key="leftBarButtonItem" title="戻る" id="aaD-A8-qxu">
29 <connections>
30 <action selector="cancelButtonClicked:" destination="-1" id="92j-lv-7mZ"/>
31 </connections>
32 </barButtonItem>
33 <barButtonItem key="rightBarButtonItem" title="保存" id="tfS-NB-bAa">
34 <connections>
35 <action selector="saveButtonClicked:" destination="-1" id="Ct8-Yt-cqf"/>
36 </connections>
37 </barButtonItem>
38 </navigationItem>
39 </items>
40 </navigationBar>
41 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="PpR-jP-zBp">
42 <rect key="frame" x="140" y="121" width="94" height="30"/>
43 <state key="normal" title="サウンド OFF"/>
44 <connections>
45 <action selector="btn0:" destination="-1" eventType="touchUpInside" id="D2i-qV-r6l"/>
46 </connections>
47 </button>
48 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AoY-L8-av3">
49 <rect key="frame" x="143" y="184" width="88" height="30"/>
50 <state key="normal" title="サウンド ON"/>
51 <connections>
52 <action selector="btn1:" destination="-1" eventType="touchUpInside" id="YsA-cp-CR4"/>
53 </connections>
54 </button>
55 </subviews>
56 <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
57 <constraints>
58 <constraint firstItem="PpR-jP-zBp" firstAttribute="top" secondItem="MGO-KK-hkK" secondAttribute="bottom" constant="54" id="4bz-HU-IHi"/>
59 <constraint firstItem="AoY-L8-av3" firstAttribute="top" secondItem="PpR-jP-zBp" secondAttribute="bottom" constant="33" id="BWX-2h-now"/>
60 <constraint firstItem="MGO-KK-hkK" firstAttribute="centerX" secondItem="PpR-jP-zBp" secondAttribute="centerX" id="HE0-AV-Sn0"/>
61 <constraint firstItem="MGO-KK-hkK" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="JBI-H3-7oh"/>
62 <constraint firstItem="PpR-jP-zBp" firstAttribute="centerX" secondItem="AoY-L8-av3" secondAttribute="centerX" id="pYf-oQ-Q5a"/>
63 <constraint firstAttribute="trailing" secondItem="MGO-KK-hkK" secondAttribute="trailing" id="rjh-dO-gU9"/>
64 <constraint firstItem="MGO-KK-hkK" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="23" id="vcv-dy-VMf"/>
65 </constraints>
66 </view>
67 <barButtonItem title="Item" id="kIx-dO-d7Q"/>
68 </objects>
69 </document>
1 //
2 // Operation.h
3 // tuber
4 //
5 // Created by ドラッサル 亜嵐 on 2016/06/09.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <Foundation/Foundation.h>
10 #import "AFNetworking.h"
11
12 @interface Operation : NSObject
13
14 @property (nonatomic, strong) AFHTTPSessionManager *manager;
15 @property (nonatomic, strong) AFHTTPSessionManager *managerCustom;
16 @property (nonatomic, strong) AFHTTPSessionManager *managerImage;
17 @property (nonatomic, strong) AFHTTPSessionManager *managerRaw;
18 @property (nonatomic, strong) AFHTTPSessionManager *managerStreamToFile;
19
20 @property (nonatomic, strong) NSString *pcbDeviceId;
21 @property (nonatomic, strong) NSString *pcbDeviceType;
22 @property (nonatomic, strong) NSString *pcbDeviceModel;
23 @property (nonatomic, strong) NSString *pcbDeviceOs;
24
25 - (void)getFirmwareList:(NSString*)deviceId
26 deviceType:(NSString*)deviceType
27 deviceModel:(NSString*)deviceModel
28 deviceOs:(NSString*)deviceOs
29 appVersion:(NSString*)appVersion
30 success:(void(^)(id JSON))successHandler
31 failure:(void(^)(NSError *error, id JSON))failureHandler;
32 - (void)getImage:(NSString*)urlString success:(void(^)(id JSON))successHandler failure:(void(^)(NSError *error, id JSON))failureHandler;
33 - (void)getRaw:(NSString*)urlString
34 success:(void(^)(id JSON))successHandler
35 failure:(void(^)(NSError *error, id JSON))failureHandler;
36 - (UIImage*)getImageFromFile:(NSString*)filename;
37 - (void)streamToFile:(NSString*)urlString
38 saveToPath:(NSString*)saveToPath
39 progressBlock:(void(^)(double fractionCompleted))progressBlock
40 success:(void(^)(NSString *savedTo))successHandler
41 failure:(void(^)(NSError *error))failureHandler;
42 + (instancetype)sharedOperation;
43
44 @end
1 //
2 // Operation.m
3 // tuber
4 //
5 // Created by ドラッサル 亜嵐 on 2016/06/09.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "Operation.h"
10 #import "AFNetworking.h"
11
12 @interface Operation () {
13 NSLock* _lock;
14 NSArray *_enableCountryNames;
15 NSArray *_enableCountryCodes;
16 }
17
18 @end
19
20 @implementation Operation
21
22 - (void)getFirmwareList:(NSString*)deviceId
23 deviceType:(NSString*)deviceType
24 deviceModel:(NSString*)deviceModel
25 deviceOs:(NSString*)deviceOs
26 appVersion:(NSString*)appVersion
27 success:(void(^)(id JSON))successHandler
28 failure:(void(^)(NSError *error, id JSON))failureHandler {
29
30 NSMutableDictionary *params = [NSMutableDictionary dictionary];
31
32 [params setObject:deviceId forKey:@"deviceid"];
33 [params setObject:deviceType forKey:@"devicetype"];
34 [params setObject:deviceModel forKey:@"devicemodel"];
35 [params setObject:deviceOs forKey:@"deviceos"];
36 [params setObject:appVersion forKey:@"appversion"];
37
38 params = [self buildParams:params needAuth:NO];
39 [self startOperationWithParams:params
40 reqApi:@"firmware_list.php"
41 method:@"GET"
42 success:^(id JSON) {
43 if (successHandler) {
44 successHandler(JSON);
45 }
46 }
47 failure:^(NSError *error, id JSON) {
48 //NSLog(@"ERROR %@", error);
49 if (failureHandler) {
50 failureHandler(error, JSON);
51 }
52 }];
53 }
54
55 - (void)getImage:(NSString*)urlString
56 success:(void(^)(id JSON))successHandler
57 failure:(void(^)(NSError *error, id JSON))failureHandler {
58
59 NSMutableDictionary *params = [NSMutableDictionary dictionary];
60
61 params = [self buildParams:params needAuth:NO];
62 [self startImageOperationWithParams:params
63 path:urlString
64 method:@"GET"
65 success:^(id JSON) {
66 if (successHandler) {
67 successHandler(JSON);
68 }
69 }
70 failure:^(NSError *error, id JSON) {
71 //NSLog(@"ERROR %@", error);
72 if (failureHandler) {
73 failureHandler(error, JSON);
74 }
75 }];
76 }
77
78 - (void)getRaw:(NSString*)urlString
79 success:(void(^)(id JSON))successHandler
80 failure:(void(^)(NSError *error, id JSON))failureHandler {
81
82 NSMutableDictionary *params = [NSMutableDictionary dictionary];
83
84 params = [self buildParams:params needAuth:NO];
85 [self startRawOperationWithParams:params
86 path:urlString
87 method:@"GET"
88 success:^(id JSON) {
89 if (successHandler) {
90 successHandler(JSON);
91 }
92 }
93 failure:^(NSError *error, id JSON) {
94 //NSLog(@"ERROR %@", error);
95 if (failureHandler) {
96 failureHandler(error, JSON);
97 }
98 }];
99 }
100
101 - (void)streamToFile:(NSString*)urlString
102 saveToPath:(NSString*)saveToPath
103 progressBlock:(void(^)(double fractionCompleted))progressBlock
104 success:(void(^)(NSString *savedTo))successHandler
105 failure:(void(^)(NSError *error))failureHandler {
106 NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
107 AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
108
109 NSURL *URL = [NSURL URLWithString:urlString];
110 NSURLRequest *request = [NSURLRequest requestWithURL:URL];
111
112
113
114 NSError *error;
115 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
116 NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
117 NSString *saveToPathFull = [documentsDirectory stringByAppendingPathComponent:saveToPath];
118
119 BOOL ex = [[NSFileManager defaultManager] fileExistsAtPath:saveToPathFull];
120 if(ex) {
121 NSLog(@"file exists: %@", saveToPathFull);
122 NSFileManager *fileManager = [NSFileManager defaultManager];
123 BOOL success = [fileManager removeItemAtPath:saveToPathFull error:&error];
124 if(success) {
125 NSLog(@"削除した");
126 } else {
127 NSLog(@"削除を失敗した");
128 }
129 } else {
130 NSLog(@"file does not exist: %@", saveToPathFull);
131 }
132
133
134 NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request
135 progress:^(NSProgress * _Nonnull downloadProgress) {
136 //NSLog(@"Progress: %f", downloadProgress.fractionCompleted);
137 dispatch_async(dispatch_get_main_queue(), ^{
138 progressBlock(downloadProgress.fractionCompleted);
139 });
140 }
141 destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
142 NSError *error;
143 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
144 NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
145 NSString *saveToPathFull = [documentsDirectory stringByAppendingPathComponent:saveToPath];
146 NSString *saveToFolder = [saveToPathFull stringByDeletingLastPathComponent];
147 if (![[NSFileManager defaultManager] fileExistsAtPath:saveToFolder])
148 {
149 [[NSFileManager defaultManager] createDirectoryAtPath:saveToFolder withIntermediateDirectories:NO attributes:nil error:&error];
150 }
151
152 NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
153 //return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
154 return [documentsDirectoryURL URLByAppendingPathComponent:saveToPath];
155 } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
156 if(!error) {
157 //NSLog(@"File downloaded to: %@", filePath);
158 successHandler([NSString stringWithFormat:@"%@",filePath]);
159 } else {
160 failureHandler(error);
161 }
162 }];
163 [downloadTask resume];
164 }
165
166 - (UIImage*)getImageFromFile:(NSString*)filename {
167 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
168 NSUserDomainMask, YES);
169 NSString *documentsDirectory = [paths objectAtIndex:0];
170 NSString* path = [documentsDirectory stringByAppendingPathComponent:
171 [NSString stringWithFormat: @"/save/%@",filename]];
172 UIImage* image = [UIImage imageWithContentsOfFile:path];
173 return image;
174 }
175
176 # pragma mark - Singleton pattern
177
178 static Operation *_sharedOperation;
179
180 - (id)init {
181 self = [super init];
182 if (self) {
183 // 初期処理
184 _lock = [[NSLock alloc] init];
185 }
186 return self;
187 }
188
189 + (instancetype)sharedOperation {
190 @synchronized(self) {
191 if (_sharedOperation == nil) {
192 (void) [[self alloc] init]; // ここでは代入していない
193 }
194 }
195 return _sharedOperation;
196 }
197
198 + (id)allocWithZone:(NSZone *)zone {
199 @synchronized(self) {
200 if (_sharedOperation == nil) {
201 _sharedOperation = [super allocWithZone:zone];
202 return _sharedOperation; // 最初の割り当てで代入し、返す
203 }
204 }
205 return nil;
206 }
207
208 - (id)copyWithZone:(NSZone *)zone {
209 return self;
210 }
211
212 #pragma mark - Private Methods
213
214 - (void)startOperationWithParams:(NSDictionary *)aParams
215 reqApi:(NSString *)reqApi
216 method:(NSString *)method
217 success:(void(^)(id JSON))successHandler
218 failure:(void(^)(NSError *error, id JSON))failureHandler {
219
220 NSString *reqApiFull = [NSString stringWithFormat:URL_PATH_API, reqApi];
221 NSString *reqUrlFull = [NSString stringWithFormat:@"%@%@", URL_BASE,reqApiFull];
222
223 [self startOperationWithParams:aParams reqUrlFull:reqUrlFull method:method success:successHandler failure:failureHandler];
224 }
225
226 - (void)startOperationWithParams:(NSDictionary *)aParams
227 reqUrlFull:(NSString *)reqUrlFull
228 method:(NSString *)method
229 success:(void(^)(id JSON))successHandler
230 failure:(void(^)(NSError *error, id JSON))failureHandler {
231
232 // form-urlencoded request
233 NSURL *URL = [NSURL URLWithString:reqUrlFull];
234
235 // set self.manager only if it hasn't been created yet
236 if(!self.managerCustom)
237 {
238 self.managerCustom = [AFHTTPSessionManager manager]; // 71%
239 //self.manager.requestSerializer = [AFJSONRequestSerializer serializer];
240 self.managerCustom.responseSerializer = [AFHTTPResponseSerializer serializer]; // 9.7%
241 self.managerCustom.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"application/x-www-form-urlencoded", nil];
242
243 }
244 /*
245 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
246 [manager setResponseSerializer:[AFHTTPResponseSerializer serializer]];
247 */
248
249 NSMutableDictionary *params = [self buildParams:aParams needAuth:NO];
250 /*
251 NSMutableURLRequest *request = [httpClient requestWithMethod:method
252 path:path
253 parameters:params];
254 [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"content-type"];
255 */
256
257 if([method isEqualToString:@"GET"]) {
258 [self.managerCustom GET:URL.absoluteString parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) {
259 if([responseObject isKindOfClass:[NSDictionary class]]) {
260 if(successHandler) {
261 successHandler(responseObject);
262 }
263 }
264 else {
265 NSDictionary *response = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:nil];
266 NSLog(@"[Operation] => resultObject: %@", response);
267 if(!response) {
268 NSMutableDictionary *queryStringDictionary = [[NSMutableDictionary alloc] init];
269 NSString * responseString = [[NSString alloc] initWithBytes:(char *)[responseObject bytes] length:[responseObject length] encoding:NSUTF8StringEncoding];
270 NSArray *urlComponents = [responseString componentsSeparatedByString:@"&"];
271
272 for (NSString *keyValuePair in urlComponents)
273 {
274 NSArray *pairComponents = [keyValuePair componentsSeparatedByString:@"="];
275 NSString *key = [[pairComponents firstObject] stringByRemovingPercentEncoding];
276 NSString *value = [[pairComponents lastObject] stringByRemovingPercentEncoding];
277
278 value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "];
279 value = [value stringByRemovingPercentEncoding];
280
281 [queryStringDictionary setObject:value forKey:key];
282 }
283 response = queryStringDictionary;
284 }
285 if(successHandler) {
286 successHandler(response);
287 }
288 }
289 } failure:^(NSURLSessionTask *operation, NSError *error) {
290 //NSLog(@"[Operation] => resultObject: %@", responseObject);
291 NSLog(@"[Operation] => error: %@", error);
292 if (failureHandler) {
293 //failureHandler(error, responseObject);
294 failureHandler(error, nil);
295 }
296 }];
297 } else if([method isEqualToString:@"POST"]) {
298 [self.managerCustom POST:URL.absoluteString parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) {
299 if([responseObject isKindOfClass:[NSDictionary class]]) {
300 if(successHandler) {
301 successHandler(responseObject);
302 }
303 }
304 else {
305 NSLog(@"[Operation] => resultObject: %@", responseObject);
306 NSDictionary *response = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:nil];
307 if(successHandler) {
308 successHandler(response);
309 }
310 }
311 } failure:^(NSURLSessionTask *operation, NSError *error) {
312 //NSLog(@"[Operation] => resultObject: %@", responseObject);
313 NSLog(@"[Operation] => error: %@", error);
314 if (failureHandler) {
315 //failureHandler(error, responseObject);
316 failureHandler(error, nil);
317 }
318 }];
319 }
320
321 //NSLog(@"[Operation] => startResuest: %@", [[request URL] absoluteString]);
322 NSLog(@"[Operation] => params: %@", params);
323 }
324
325 - (void)startImageOperationWithParams:(NSDictionary *)aParams
326 path:(NSString *)pathString
327 method:(NSString *)method
328 success:(void(^)(id JSON))successHandler
329 failure:(void(^)(NSError *error, id JSON))failureHandler {
330 [self startImageOperationWithParams:aParams reqPath:@"%@" path:pathString method:method success:successHandler failure:failureHandler];
331 }
332
333 - (void)startImageOperationWithParams:(NSDictionary *)aParams
334 reqPath:(NSString *)reqPathStr
335 path:(NSString *)pathString
336 method:(NSString *)method
337 success:(void(^)(id JSON))successHandler
338 failure:(void(^)(NSError *error, id JSON))failureHandler {
339
340 // form-urlencoded request
341 NSString *path = [NSString stringWithFormat:reqPathStr, pathString];
342 NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@",path]];
343
344 // set self.manager only if it hasn't been created yet
345 if(!self.managerImage)
346 {
347 self.managerImage = [AFHTTPSessionManager manager]; // 71%
348 //self.managerImage.requestSerializer = [AFJSONRequestSerializer serializer];
349 self.managerImage.responseSerializer = [AFImageResponseSerializer serializer]; // 9.7%
350 }
351 /*
352 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
353 [manager setResponseSerializer:[AFHTTPResponseSerializer serializer]];
354 */
355
356 NSMutableDictionary *params = [self buildParams:aParams needAuth:NO];
357 /*
358 NSMutableURLRequest *request = [httpClient requestWithMethod:method
359 path:path
360 parameters:params];
361 [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"content-type"];
362 */
363
364 if([method isEqualToString:@"GET"]) {
365 [self.managerImage GET:URL.absoluteString parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) {
366 NSLog(@"[Operation] => resultObject: %@", responseObject);
367 if(successHandler) {
368 successHandler(responseObject);
369 }
370 } failure:^(NSURLSessionTask *operation, NSError *error) {
371 //NSLog(@"[Operation] => resultObject: %@", responseObject);
372 NSLog(@"[Operation] => error: %@", error);
373 if (failureHandler) {
374 //failureHandler(error, responseObject);
375 failureHandler(error, nil);
376 }
377 }];
378 } else if([method isEqualToString:@"POST"]) {
379 [self.managerImage POST:URL.absoluteString parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) {
380 NSLog(@"[Operation] => resultObject: %@", responseObject);
381 if(successHandler) {
382 successHandler(responseObject);
383 }
384 } failure:^(NSURLSessionTask *operation, NSError *error) {
385 //NSLog(@"[Operation] => resultObject: %@", responseObject);
386 NSLog(@"[Operation] => error: %@", error);
387 if (failureHandler) {
388 //failureHandler(error, responseObject);
389 failureHandler(error, nil);
390 }
391 }];
392 }
393
394 //NSLog(@"[Operation] => startResuest: %@", [[request URL] absoluteString]);
395 NSLog(@"[Operation] => params: %@", params);
396 }
397
398 - (void)startRawOperationWithParams:(NSDictionary *)aParams
399 path:(NSString *)pathString
400 method:(NSString *)method
401 success:(void(^)(id JSON))successHandler
402 failure:(void(^)(NSError *error, id JSON))failureHandler {
403 [self startRawOperationWithParams:aParams reqPath:@"%@" path:pathString method:method success:successHandler failure:failureHandler];
404 }
405
406 - (void)startRawOperationWithParams:(NSDictionary *)aParams
407 reqPath:(NSString *)reqPathStr
408 path:(NSString *)pathString
409 method:(NSString *)method
410 success:(void(^)(id JSON))successHandler
411 failure:(void(^)(NSError *error, id JSON))failureHandler {
412
413 // form-urlencoded request
414 NSString *path = [NSString stringWithFormat:reqPathStr, pathString];
415 NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@",path]];
416
417 // set self.manager only if it hasn't been created yet
418 if(!self.managerRaw)
419 {
420 self.managerRaw = [AFHTTPSessionManager manager]; // 71%
421 //self.managerRaw.responseSerializer = [AFJSONRequestSerializer serializer];
422 //self.managerRaw.responseSerializer = [AFImageResponseSerializer serializer]; // 9.7%
423 self.managerRaw.responseSerializer = [AFHTTPResponseSerializer serializer]; // 9.7%
424 }
425 /*
426 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
427 [manager setResponseSerializer:[AFHTTPResponseSerializer serializer]];
428 */
429
430 NSMutableDictionary *params = [self buildParams:aParams needAuth:NO];
431 /*
432 NSMutableURLRequest *request = [httpClient requestWithMethod:method
433 path:path
434 parameters:params];
435 [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"content-type"];
436 */
437
438 if([method isEqualToString:@"GET"]) {
439 [self.managerRaw GET:URL.absoluteString parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) {
440 //NSLog(@"[Operation] => resultObject: %@", responseObject);
441 if(successHandler) {
442 successHandler(responseObject);
443 }
444 } failure:^(NSURLSessionTask *operation, NSError *error) {
445 //NSLog(@"[Operation] => resultObject: %@", responseObject);
446 NSLog(@"[Operation] => error: %@", error);
447 if (failureHandler) {
448 //failureHandler(error, responseObject);
449 failureHandler(error, nil);
450 }
451 }];
452 } else if([method isEqualToString:@"POST"]) {
453 [self.managerRaw POST:URL.absoluteString parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) {
454 //NSLog(@"[Operation] => resultObject: %@", responseObject);
455 if(successHandler) {
456 successHandler(responseObject);
457 }
458 } failure:^(NSURLSessionTask *operation, NSError *error) {
459 //NSLog(@"[Operation] => resultObject: %@", responseObject);
460 NSLog(@"[Operation] => error: %@", error);
461 if (failureHandler) {
462 //failureHandler(error, responseObject);
463 failureHandler(error, nil);
464 }
465 }];
466 }
467
468 //NSLog(@"[Operation] => startResuest: %@", [[request URL] absoluteString]);
469 NSLog(@"[Operation] => params: %@", params);
470 }
471
472 /*
473 - (void)startOperationWithParams:(NSDictionary *)aParams
474 reqPath:(NSString *)reqPathStr
475 path:(NSString *)pathString
476 method:(NSString *)method
477 success:(void(^)(id JSON))successHandler
478 failure:(void(^)(NSError *error, id JSON))failureHandler {
479
480 // form-urlencoded request
481 NSString *path = [NSString stringWithFormat:reqPathStr, pathString];
482 NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@",BASE_URL,path]];
483 NSMutableDictionary *params = [self buildParams:aParams needAuth:NO];
484
485
486
487
488
489
490
491 NSError *error;
492 NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
493 NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
494
495 AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
496
497 NSMutableURLRequest *req = [[AFJSONRequestSerializer serializer] requestWithMethod:@"POST" URLString:URL.absoluteString parameters:nil error:nil];
498
499 req.timeoutInterval= [[[NSUserDefaults standardUserDefaults] valueForKey:@"timeoutInterval"] longValue];
500 [req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
501 [req setValue:@"application/json" forHTTPHeaderField:@"Accept"];
502 //[req setHTTPBody:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];
503
504
505 NSMutableData *data = [[NSMutableData alloc] init];
506 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
507 [archiver encodeObject:params forKey:@"Some Key Value"];
508 [archiver finishEncoding];
509 // Here, data holds the serialized version of your dictionary
510 [req setHTTPBody:data];
511
512
513 [[manager dataTaskWithRequest:req completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
514
515 if (!error) {
516 if([responseObject isKindOfClass:[NSDictionary class]]) {
517 if(successHandler) {
518 successHandler(responseObject);
519 }
520 }
521 else {
522 NSDictionary *response = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:nil];
523 NSLog(@"[Operation] => resultObject: %@", response);
524 if(successHandler) {
525 successHandler(response);
526 }
527 }
528 } else {
529 //NSLog(@"[Operation] => resultObject: %@", responseObject);
530 NSLog(@"[Operation] => error: %@", error);
531 if (failureHandler) {
532 //failureHandler(error, responseObject);
533 failureHandler(error, nil);
534 }
535 }
536 }] resume];
537
538 //NSLog(@"[Operation] => startResuest: %@", [[request URL] absoluteString]);
539 NSLog(@"[Operation] => params: %@", params);
540 }
541 */
542
543 # pragma mark - Network management methods
544
545 - (NSMutableDictionary *)buildParams:(NSDictionary *)params needAuth:(BOOL)needAuth {
546 // APIの基本パラメータを生成
547 NSMutableDictionary *result = [NSMutableDictionary dictionary];
548 if (params) {
549 [result setValuesForKeysWithDictionary:params];
550 }
551 if (needAuth) {
552 NSString *username = USER_USERID;
553 if (!username)
554 username = @"";
555 NSString *password = USER_PASSWORD;
556 if (!password)
557 password = @"";
558 [result setObject:username forKey:KEY_USER_USERID];
559 [result setObject:password forKey:KEY_USER_PASSWORD];
560 }
561 //[result setObject:@"ios" forKey:AGENT_KEY];
562 //[result setObject:@"vname" forKey:VNAME_KEY];
563 return result;
564 }
565
566 @end
1 //
2 // SettingsController.h
3 // jacketparentweb
4 //
5 // Created by Chris Johnston on 11/28/16.
6 // Copyright © 2016 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10 #import "BleProtocol.h"
11 #import "BLE.h"
12
13 typedef enum {
14 SETTINGS_CONTROLLER__EEPROM_READ_MODE,
15 SETTINGS_CONTROLLER__EEPROM_READ_MODE_DONE,
16 SETTINGS_CONTROLLER__EEPROM_READ_ID,
17 SETTINGS_CONTROLLER__EEPROM_READ_ID_DONE,
18 SETTINGS_CONTROLLER__EEPROM_READ_MODEL,
19 SETTINGS_CONTROLLER__EEPROM_READ_MODEL_DONE,
20 SETTINGS_CONTROLLER__EEPROM_READ_TYPE,
21 SETTINGS_CONTROLLER__EEPROM_READ_TYPE_DONE,
22 SETTINGS_CONTROLLER__EEPROM_READ_OS,
23 SETTINGS_CONTROLLER__EEPROM_READ_OS_DONE,
24 SETTINGS_CONTROLLER__EEPROM_READ_PIN,
25 SETTINGS_CONTROLLER__EEPROM_READ_PIN_DONE,
26 SETTINGS_CONTROLLER__DONE
27 } SettingsControllerCommandState;
28
29 @interface SettingsController : UIViewController <BLEProtocolDelegate> {
30 IBOutlet UILabel *lblDeviceMode;
31 IBOutlet UILabel *lblDeviceId;
32 IBOutlet UILabel *lblDeviceModel;
33 IBOutlet UILabel *lblDeviceType;
34 IBOutlet UILabel *lblDeviceOs;
35 IBOutlet UILabel *lblDevicePin;
36 SettingsControllerCommandState bleCommandState;
37 }
38
39 @property (nonatomic, strong) NSString *jacketId;
40 @property (strong, nonatomic) BLE *ble;
41 @property (strong, nonatomic) BleProtocol *protocol;
42 @property (nonatomic,assign) id <BLEProtocolDelegate> lastProtocolDelegate;
43
44 + (void)show:(NSString*)jacketId navigationController:(UINavigationController*)navigationController;
45
46 @end
1 //
2 // SettingsController.m
3 // jacketparentweb
4 //
5 // Created by Chris Johnston on 11/28/16.
6 // Copyright © 2016 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "SettingsController.h"
10 #import "InputMotorController.h"
11 #import "InputSoundController.h"
12 #import "FirmwareDownloadController.h"
13 #import "FirmwareUpdateController.h"
14 #import "EepromController.h"
15 #import "BootSettingController.h"
16
17 @interface SettingsController ()
18
19 @property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
20 @property (strong, nonatomic) IBOutlet UILabel *currentMotor;
21
22 @property (nonatomic) NSInteger itemCounter;
23 @property (nonatomic) NSTimer * tmr;
24
25 @end
26
27 @implementation SettingsController {
28 UIView *_mask;
29 NSTimer *_writeWalkResponseTimer;
30 NSTimer *_writeResetTimerResponseTimer;
31 bool ignoreWriteWalkResponse;
32 bool ignoreWriteResetUsetimeResponse;
33 NSArray<UILabel*>* timeRangeLabels;
34 NSMutableArray<NSString*>* timeRangeData;
35 NSArray<NSString*>* daysOfWeek;
36 }
37 @synthesize ble;
38 @synthesize protocol;
39
40 + (void)show:(BleProtocol*)protocol navigationController:(UINavigationController*)navigationController {
41 SettingsController *viewObj=[[SettingsController alloc] initWithNibName:@"SettingsController" bundle:nil];
42 viewObj.protocol = protocol;
43 [navigationController pushViewController:viewObj animated:YES];
44 }
45
46 - (void)viewDidLoad {
47 [super viewDidLoad];
48 // Do any additional setup after loading the view.
49 }
50
51 - (void)viewWillAppear:(BOOL)animated {
52 [super viewWillAppear:animated];
53
54 _lastProtocolDelegate = protocol.delegate;
55 protocol.delegate = self;
56
57 bleCommandState = SETTINGS_CONTROLLER__EEPROM_READ_ID;
58 [self bleCommandTask];
59 }
60
61 - (void)viewWillDisappear:(BOOL)animated {
62 [super viewWillDisappear:animated];
63 [self.tmr invalidate];
64 protocol.delegate = _lastProtocolDelegate;
65 }
66
67 - (void)dealloc {
68 // Do cleanup
69 }
70
71 - (void)didReceiveMemoryWarning {
72 [super didReceiveMemoryWarning];
73 // Dispose of any resources that can be recreated.
74 }
75
76 - (void)writeResetTimerResponseTimeout:(NSTimer *)timer {
77 ignoreWriteResetUsetimeResponse = true;
78 [self showAlert:@"ジャケットの設定" message:@"設定が保存されない。"];
79 }
80
81 - (NSString*)byteToDays:(NSString*)dowByte{
82 NSMutableString *result = [NSMutableString stringWithString:@""];
83 const char *chars = [dowByte UTF8String];
84 Byte byte = strtoul(chars, NULL, 16);
85 for(int i=0; i<7; i++){
86 if(byte & (1 << i)) {
87 [result appendString:[daysOfWeek objectAtIndex:i]];
88 }
89 }
90 return [NSString stringWithString:result];
91 }
92
93 - (void)showAlert:(NSString*)title message:(NSString*)message{
94 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
95 message:message
96 delegate:self
97 cancelButtonTitle:@"OK"
98 otherButtonTitles:nil];
99 [alert show];
100 }
101
102 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
103 [_mask removeFromSuperview];
104 }
105
106 - (void)showMask {
107 _mask = [[UIView alloc] initWithFrame:[self.view frame]];
108 [_mask setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0.25]];
109 [self.view addSubview:_mask];
110 }
111
112 - (IBAction)firmwareDownloadClicked:(id)sender {
113 FirmwareDownloadController *viewObj=[[FirmwareDownloadController alloc] initWithNibName:@"FirmwareDownloadController" bundle:nil];
114 viewObj.protocol = self.protocol;
115 [self presentViewController:viewObj animated:YES completion: nil];
116 }
117
118 - (IBAction)firmwareUpdateClicked:(id)sender {
119 FirmwareUpdateController *viewObj=[[FirmwareUpdateController alloc] initWithNibName:@"FirmwareUpdateController" bundle:nil];
120 viewObj.protocol = self.protocol;
121 [self presentViewController:viewObj animated:YES completion: nil];
122 }
123
124 - (IBAction)eepromUpdateClicked:(id)sender {
125 EepromController *viewObj=[[EepromController alloc] initWithNibName:@"EepromController" bundle:nil];
126 viewObj.protocol = self.protocol;
127 [self presentViewController:viewObj animated:YES completion: nil];
128 }
129
130 - (IBAction)bootUpdateClicked:(id)sender {
131 BootSettingController *viewObj=[[BootSettingController alloc] initWithNibName:@"BootSettingController" bundle:nil];
132 viewObj.protocol = self.protocol;
133 [self presentViewController:viewObj animated:YES completion: nil];
134 }
135
136 - (IBAction)InputMotorClicked:(id)sender {
137 InputMotorController *viewObj=[[InputMotorController alloc] initWithNibName:@"InputMotorController" bundle:nil];
138 viewObj.protocol = self.protocol;
139 [self presentViewController:viewObj animated:YES completion: nil];
140 }
141
142 - (IBAction)InputSoundClicked:(id)sender {
143 InputSoundController *viewObj=[[InputSoundController alloc] initWithNibName:@"InputSoundController" bundle:nil];
144 viewObj.protocol = self.protocol;
145 [self presentViewController:viewObj animated:YES completion: nil];
146 }
147
148 - (IBAction)resetClicked:(id)sender {
149 [[self protocol]putData:@"systemReset" data:nil];
150 }
151
152 - (IBAction)updateModeResetClicked:(id)sender {
153 [[self protocol]putData:@"eepromWriteProtect" data:@"0"];
154 }
155
156 - (BOOL)bleCommandTask {
157 switch(bleCommandState) {
158 case SETTINGS_CONTROLLER__EEPROM_READ_MODE:
159 [[self protocol]putData:@"infoDeviceId" data:nil];
160 break;
161 case SETTINGS_CONTROLLER__EEPROM_READ_ID:
162 [[self protocol]putData:@"infoDeviceId" data:nil];
163 break;
164 case SETTINGS_CONTROLLER__EEPROM_READ_MODEL:
165 [[self protocol]putData:@"infoDeviceModel" data:nil];
166 break;
167 case SETTINGS_CONTROLLER__EEPROM_READ_TYPE:
168 [[self protocol]putData:@"infoDeviceType" data:nil];
169 break;
170 case SETTINGS_CONTROLLER__EEPROM_READ_OS:
171 [[self protocol]putData:@"infoDeviceOs" data:nil];
172 break;
173 case SETTINGS_CONTROLLER__EEPROM_READ_PIN:
174 [[self protocol]putData:@"infoDevicePin" data:nil];
175 break;
176 case SETTINGS_CONTROLLER__EEPROM_READ_MODE_DONE:
177 bleCommandState = SETTINGS_CONTROLLER__EEPROM_READ_ID;
178 [self bleCommandTask];
179 break;
180 case SETTINGS_CONTROLLER__EEPROM_READ_ID_DONE:
181 bleCommandState = SETTINGS_CONTROLLER__EEPROM_READ_MODEL;
182 [self bleCommandTask];
183 break;
184 case SETTINGS_CONTROLLER__EEPROM_READ_MODEL_DONE:
185 bleCommandState = SETTINGS_CONTROLLER__EEPROM_READ_TYPE;
186 [self bleCommandTask];
187 break;
188 case SETTINGS_CONTROLLER__EEPROM_READ_TYPE_DONE:
189 bleCommandState = SETTINGS_CONTROLLER__EEPROM_READ_OS;
190 [self bleCommandTask];
191 break;
192 case SETTINGS_CONTROLLER__EEPROM_READ_OS_DONE:
193 bleCommandState = SETTINGS_CONTROLLER__EEPROM_READ_PIN;
194 [self bleCommandTask];
195 break;
196 case SETTINGS_CONTROLLER__EEPROM_READ_PIN_DONE:
197 bleCommandState = SETTINGS_CONTROLLER__DONE;
198 [self bleCommandTask];
199 break;
200 case SETTINGS_CONTROLLER__DONE:
201 {
202 NSLog(@"Ble command set done!");
203 break;
204 }
205 }
206 return false;
207 }
208
209 - (void)protocolDidGetData:(NSString *)dataType data:(NSString *)dataData {
210 NSString *dataTypeFixed;
211
212 if([dataType hasPrefix:@"read"]) {
213 dataTypeFixed = [NSString stringWithFormat:@"%@%@",[[dataType substringWithRange:NSMakeRange(4, 1)] lowercaseString], [dataType substringFromIndex:5]];
214
215 //NSLog(@"[SettingsController] read dataTypeFixed: %@", dataTypeFixed);
216
217 if([dataData isEqualToString:@""]) {
218 dataData = @"なし";
219 }
220
221 if([dataTypeFixed isEqualToString:@"motor"]) {
222 _currentMotor.text = dataData;
223 }
224
225 //NSLog(@"[SettingsController] read dataData: %@", dataData);
226 } else if([dataType hasPrefix:@"write"]) {
227 dataTypeFixed = [NSString stringWithFormat:@"%@%@",[[dataType substringWithRange:NSMakeRange(5, 1)] lowercaseString], [dataType substringFromIndex:6]];
228 //NSLog(@"[SettingsController] write dataTypeFixed: %@", dataTypeFixed);
229 //NSLog(@"[SettingsController] write dataData: %@", dataData);
230
231 if([dataTypeFixed isEqual:@"walking"]) {
232 if(ignoreWriteWalkResponse) return;
233 [_writeWalkResponseTimer invalidate];
234
235 if([dataData isEqual:@"OK"]) {
236 [self showAlert:@"ジャケットの設定" message:@"設定が保存されました。"];
237 } else {
238 [self showAlert:@"ジャケットの設定" message:@"設定が保存されない。"];
239 }
240 }
241 } else if([dataType isEqualToString:@"eepromWriteProtect"]) {
242 [[self protocol]putData:@"systemResetInBootloader" data:nil];
243 } else if([dataType isEqualToString:@"infoDeviceMode"]) {
244 NSLog(@"infoDeviceMode");
245 lblDeviceMode.text = dataData;
246 bleCommandState = SETTINGS_CONTROLLER__EEPROM_READ_MODE_DONE;
247 [self bleCommandTask];
248 } else if([dataType isEqualToString:@"infoDeviceId"]) {
249 NSLog(@"infoDeviceId");
250 lblDeviceId.text = dataData;
251 bleCommandState = SETTINGS_CONTROLLER__EEPROM_READ_ID_DONE;
252 [self bleCommandTask];
253 } else if([dataType isEqualToString:@"infoDeviceModel"]) {
254 NSLog(@"infoDeviceModel");
255 lblDeviceModel.text = dataData;
256 bleCommandState = SETTINGS_CONTROLLER__EEPROM_READ_MODEL_DONE;
257 [self bleCommandTask];
258 } else if([dataType isEqualToString:@"infoDeviceType"]) {
259 NSLog(@"infoDeviceType");
260 lblDeviceType.text = dataData;
261 bleCommandState = SETTINGS_CONTROLLER__EEPROM_READ_TYPE_DONE;
262 [self bleCommandTask];
263 } else if([dataType isEqualToString:@"infoDeviceOs"]) {
264 NSLog(@"infoDeviceOs");
265 lblDeviceOs.text = dataData;
266 if([dataData hasPrefix:@"B"]) {
267 lblDeviceMode.text = @"UPDATE";
268 } else {
269 lblDeviceMode.text = @"APPLICATION";
270 }
271 bleCommandState = SETTINGS_CONTROLLER__EEPROM_READ_OS_DONE;
272 [self bleCommandTask];
273 } else if([dataType isEqualToString:@"infoDevicePin"]) {
274 NSLog(@"infoDevicePin");
275 lblDevicePin.text = dataData;
276 bleCommandState = SETTINGS_CONTROLLER__EEPROM_READ_PIN_DONE;
277 [self bleCommandTask];
278 }
279 }
280
281 @end
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
3 <device id="retina4_0" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <deployment identifier="iOS"/>
8 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13173"/>
9 <capability name="Alignment constraints to the first baseline" minToolsVersion="6.0"/>
10 <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
11 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
12 </dependencies>
13 <objects>
14 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SettingsController">
15 <connections>
16 <outlet property="lblDeviceId" destination="R0e-ju-3rJ" id="Eb4-9O-Agt"/>
17 <outlet property="lblDeviceMode" destination="7Md-pz-rS9" id="0KH-nO-VgJ"/>
18 <outlet property="lblDeviceModel" destination="FQe-8d-toS" id="ebO-2N-5hW"/>
19 <outlet property="lblDeviceOs" destination="wTV-GF-cUt" id="KYf-7B-NrH"/>
20 <outlet property="lblDevicePin" destination="xoE-0o-rQI" id="l2r-ul-pci"/>
21 <outlet property="lblDeviceType" destination="edw-Vo-Bc5" id="GJa-h4-p8m"/>
22 <outlet property="scrollView" destination="Gq0-Ni-ZRy" id="WzG-xH-2dU"/>
23 <outlet property="view" destination="i5M-Pr-FkT" id="dA6-dK-EZ0"/>
24 </connections>
25 </placeholder>
26 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
27 <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
28 <rect key="frame" x="0.0" y="0.0" width="320" height="783"/>
29 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
30 <subviews>
31 <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" ambiguous="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Gq0-Ni-ZRy">
32 <rect key="frame" x="0.0" y="0.0" width="320" height="783"/>
33 <subviews>
34 <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cfc-hT-fKj" customClass="DemoView" customModule="jacket_test_ios" customModuleProvider="target">
35 <rect key="frame" x="0.0" y="0.0" width="320" height="775"/>
36 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
37 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
38 </view>
39 </subviews>
40 </scrollView>
41 </subviews>
42 <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
43 <constraints>
44 <constraint firstAttribute="bottom" secondItem="Gq0-Ni-ZRy" secondAttribute="bottom" id="3Lo-bZ-bNw"/>
45 <constraint firstItem="Gq0-Ni-ZRy" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="Ay0-Jm-RMi"/>
46 <constraint firstAttribute="trailing" secondItem="Gq0-Ni-ZRy" secondAttribute="trailing" id="vvl-Sz-2e2"/>
47 <constraint firstItem="Gq0-Ni-ZRy" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="y1K-nD-sXF"/>
48 </constraints>
49 <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
50 <point key="canvasLocation" x="-112" y="2427.5"/>
51 </view>
52 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uMf-cM-5yr" userLabel="Content">
53 <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
54 <subviews>
55 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eIE-UX-Coo" userLabel="BootUpdate">
56 <rect key="frame" x="0.0" y="0.0" width="320" height="180"/>
57 <subviews>
58 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="基板の情報" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="B0g-wP-AkO">
59 <rect key="frame" x="0.0" y="0.0" width="320" height="34"/>
60 <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
61 <constraints>
62 <constraint firstAttribute="height" constant="34" id="JkZ-zf-mDP"/>
63 </constraints>
64 <fontDescription key="fontDescription" type="system" pointSize="17"/>
65 <nil key="textColor"/>
66 <nil key="highlightedColor"/>
67 </label>
68 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ID" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Eh3-6e-3UV">
69 <rect key="frame" x="8" y="62" width="69" height="21"/>
70 <constraints>
71 <constraint firstAttribute="width" constant="69" id="Mjr-RX-kkM"/>
72 </constraints>
73 <fontDescription key="fontDescription" type="system" pointSize="17"/>
74 <nil key="textColor"/>
75 <nil key="highlightedColor"/>
76 </label>
77 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="モード" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fvS-r5-fcl">
78 <rect key="frame" x="8" y="38" width="69" height="21"/>
79 <constraints>
80 <constraint firstAttribute="width" constant="69" id="XZQ-7I-ohk"/>
81 </constraints>
82 <fontDescription key="fontDescription" type="system" pointSize="17"/>
83 <nil key="textColor"/>
84 <nil key="highlightedColor"/>
85 </label>
86 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Z60-Ov-osn">
87 <rect key="frame" x="118" y="42" width="142" height="21"/>
88 <constraints>
89 <constraint firstAttribute="width" constant="142" id="nBq-pg-NGj"/>
90 </constraints>
91 <fontDescription key="fontDescription" type="system" pointSize="17"/>
92 <nil key="textColor"/>
93 <nil key="highlightedColor"/>
94 </label>
95 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="MODEL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OfR-lz-RdI">
96 <rect key="frame" x="8" y="85" width="69" height="21"/>
97 <constraints>
98 <constraint firstAttribute="width" constant="69" id="jNU-gH-Hmy"/>
99 </constraints>
100 <fontDescription key="fontDescription" type="system" pointSize="17"/>
101 <nil key="textColor"/>
102 <nil key="highlightedColor"/>
103 </label>
104 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="TYPE" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ciF-HT-7im">
105 <rect key="frame" x="8" y="109" width="69" height="21"/>
106 <constraints>
107 <constraint firstAttribute="width" constant="69" id="rI7-Bd-FLA"/>
108 </constraints>
109 <fontDescription key="fontDescription" type="system" pointSize="17"/>
110 <nil key="textColor"/>
111 <nil key="highlightedColor"/>
112 </label>
113 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="OS" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ulk-TS-1YW">
114 <rect key="frame" x="8" y="130" width="69" height="21"/>
115 <constraints>
116 <constraint firstAttribute="width" constant="69" id="uaF-7h-MDM"/>
117 </constraints>
118 <fontDescription key="fontDescription" type="system" pointSize="17"/>
119 <nil key="textColor"/>
120 <nil key="highlightedColor"/>
121 </label>
122 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="PIN" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eW2-wE-Y8r" userLabel="Lbl Device Pin">
123 <rect key="frame" x="8" y="151" width="27" height="21"/>
124 <fontDescription key="fontDescription" type="system" pointSize="17"/>
125 <nil key="textColor"/>
126 <nil key="highlightedColor"/>
127 </label>
128 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="取得中" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="R0e-ju-3rJ">
129 <rect key="frame" x="75" y="66" width="236" height="17"/>
130 <fontDescription key="fontDescription" type="system" pointSize="14"/>
131 <nil key="textColor"/>
132 <nil key="highlightedColor"/>
133 </label>
134 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="取得中" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FQe-8d-toS">
135 <rect key="frame" x="75" y="85" width="236" height="21"/>
136 <fontDescription key="fontDescription" type="system" pointSize="14"/>
137 <nil key="textColor"/>
138 <nil key="highlightedColor"/>
139 </label>
140 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="取得中" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="edw-Vo-Bc5">
141 <rect key="frame" x="75" y="108" width="236" height="21"/>
142 <constraints>
143 <constraint firstAttribute="height" constant="21" id="Zur-HE-k73"/>
144 </constraints>
145 <fontDescription key="fontDescription" type="system" pointSize="14"/>
146 <nil key="textColor"/>
147 <nil key="highlightedColor"/>
148 </label>
149 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="取得中" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wTV-GF-cUt">
150 <rect key="frame" x="75" y="131" width="236" height="17"/>
151 <fontDescription key="fontDescription" type="system" pointSize="14"/>
152 <nil key="textColor"/>
153 <nil key="highlightedColor"/>
154 </label>
155 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="取得中" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7Md-pz-rS9">
156 <rect key="frame" x="269" y="38" width="43" height="17"/>
157 <fontDescription key="fontDescription" type="system" pointSize="14"/>
158 <nil key="textColor"/>
159 <nil key="highlightedColor"/>
160 </label>
161 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="取得中" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xoE-0o-rQI" userLabel="Lbl Device Pin">
162 <rect key="frame" x="268" y="151" width="43" height="17"/>
163 <fontDescription key="fontDescription" type="system" pointSize="14"/>
164 <nil key="textColor"/>
165 <nil key="highlightedColor"/>
166 </label>
167 </subviews>
168 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
169 <constraints>
170 <constraint firstItem="edw-Vo-Bc5" firstAttribute="top" secondItem="FQe-8d-toS" secondAttribute="bottom" constant="2" id="0sm-wS-Cfx"/>
171 <constraint firstItem="eW2-wE-Y8r" firstAttribute="top" secondItem="Ulk-TS-1YW" secondAttribute="bottom" id="4Pl-XC-ENT"/>
172 <constraint firstAttribute="trailing" secondItem="B0g-wP-AkO" secondAttribute="trailing" id="5dD-IQ-w6L"/>
173 <constraint firstItem="R0e-ju-3rJ" firstAttribute="trailing" secondItem="FQe-8d-toS" secondAttribute="trailing" id="6T2-Rw-zVC"/>
174 <constraint firstItem="Z60-Ov-osn" firstAttribute="leading" secondItem="Eh3-6e-3UV" secondAttribute="trailing" constant="41" id="6t6-in-NnI"/>
175 <constraint firstItem="Z60-Ov-osn" firstAttribute="baseline" secondItem="Eh3-6e-3UV" secondAttribute="baseline" constant="-20" id="8XO-4P-5Gh"/>
176 <constraint firstItem="OfR-lz-RdI" firstAttribute="leading" secondItem="Ulk-TS-1YW" secondAttribute="leading" id="8z3-5W-41D"/>
177 <constraint firstAttribute="trailing" secondItem="xoE-0o-rQI" secondAttribute="trailing" constant="9" id="AFL-eS-ZnM"/>
178 <constraint firstItem="7Md-pz-rS9" firstAttribute="top" secondItem="B0g-wP-AkO" secondAttribute="bottom" constant="4" id="FkS-OY-9AO"/>
179 <constraint firstItem="R0e-ju-3rJ" firstAttribute="leading" secondItem="FQe-8d-toS" secondAttribute="leading" id="JGf-RB-Gkl"/>
180 <constraint firstItem="R0e-ju-3rJ" firstAttribute="leading" secondItem="eIE-UX-Coo" secondAttribute="leading" constant="75" id="LBg-Qb-exN"/>
181 <constraint firstItem="ciF-HT-7im" firstAttribute="top" secondItem="OfR-lz-RdI" secondAttribute="bottom" constant="3" id="OTz-Xb-8RD"/>
182 <constraint firstItem="Eh3-6e-3UV" firstAttribute="leading" secondItem="eIE-UX-Coo" secondAttribute="leading" constant="8" id="PPS-1m-wpu"/>
183 <constraint firstItem="R0e-ju-3rJ" firstAttribute="trailing" secondItem="eIE-UX-Coo" secondAttribute="trailingMargin" constant="-1" id="Q0C-E0-vsI"/>
184 <constraint firstItem="R0e-ju-3rJ" firstAttribute="leading" secondItem="edw-Vo-Bc5" secondAttribute="leading" id="TcD-PW-YNW"/>
185 <constraint firstAttribute="trailing" secondItem="R0e-ju-3rJ" secondAttribute="trailing" constant="9" id="U78-7L-mib"/>
186 <constraint firstItem="fvS-r5-fcl" firstAttribute="leading" secondItem="eIE-UX-Coo" secondAttribute="leading" constant="8" id="Usz-9a-iEF"/>
187 <constraint firstItem="wTV-GF-cUt" firstAttribute="top" secondItem="edw-Vo-Bc5" secondAttribute="bottom" constant="2" id="V2z-ol-bKf"/>
188 <constraint firstItem="eW2-wE-Y8r" firstAttribute="leading" secondItem="eIE-UX-Coo" secondAttribute="leading" constant="8" id="Vf6-Ek-S4h"/>
189 <constraint firstItem="xoE-0o-rQI" firstAttribute="top" secondItem="wTV-GF-cUt" secondAttribute="bottom" constant="3" id="bHE-HM-JA3"/>
190 <constraint firstItem="xoE-0o-rQI" firstAttribute="top" secondItem="wTV-GF-cUt" secondAttribute="bottom" constant="3" id="bzm-rp-NAz"/>
191 <constraint firstItem="OfR-lz-RdI" firstAttribute="leading" secondItem="Eh3-6e-3UV" secondAttribute="leading" id="c7l-L8-Jsi"/>
192 <constraint firstItem="fvS-r5-fcl" firstAttribute="top" secondItem="B0g-wP-AkO" secondAttribute="bottom" constant="4" id="dCu-tP-7RX"/>
193 <constraint firstItem="edw-Vo-Bc5" firstAttribute="baseline" secondItem="ciF-HT-7im" secondAttribute="baseline" id="emT-q3-zXA"/>
194 <constraint firstItem="Eh3-6e-3UV" firstAttribute="leading" secondItem="eIE-UX-Coo" secondAttribute="leading" constant="8" id="fen-9e-2Km"/>
195 <constraint firstItem="Z60-Ov-osn" firstAttribute="firstBaseline" secondItem="Eh3-6e-3UV" secondAttribute="baseline" constant="-20" id="gAS-O9-Yht"/>
196 <constraint firstItem="B0g-wP-AkO" firstAttribute="top" secondItem="eIE-UX-Coo" secondAttribute="top" id="hP1-Bd-CeX"/>
197 <constraint firstItem="Ulk-TS-1YW" firstAttribute="top" secondItem="ciF-HT-7im" secondAttribute="bottom" id="kSk-bE-Iln"/>
198 <constraint firstItem="R0e-ju-3rJ" firstAttribute="top" secondItem="Z60-Ov-osn" secondAttribute="bottom" constant="3" id="kZp-Iu-YU9"/>
199 <constraint firstItem="R0e-ju-3rJ" firstAttribute="trailing" secondItem="edw-Vo-Bc5" secondAttribute="trailing" id="me4-d1-SVv"/>
200 <constraint firstItem="Eh3-6e-3UV" firstAttribute="top" secondItem="fvS-r5-fcl" secondAttribute="bottom" constant="3" id="n7d-JU-q0a"/>
201 <constraint firstItem="B0g-wP-AkO" firstAttribute="leading" secondItem="eIE-UX-Coo" secondAttribute="leading" id="qDe-NH-yu6"/>
202 <constraint firstItem="wTV-GF-cUt" firstAttribute="leading" secondItem="edw-Vo-Bc5" secondAttribute="leading" id="r9h-pD-CBi"/>
203 <constraint firstItem="OfR-lz-RdI" firstAttribute="top" secondItem="Z60-Ov-osn" secondAttribute="bottom" constant="22" id="rhw-YN-J64"/>
204 <constraint firstItem="wTV-GF-cUt" firstAttribute="trailing" secondItem="edw-Vo-Bc5" secondAttribute="trailing" id="tEP-2z-MME"/>
205 <constraint firstItem="FQe-8d-toS" firstAttribute="top" secondItem="Z60-Ov-osn" secondAttribute="bottom" constant="22" id="vYd-SU-RCn"/>
206 <constraint firstItem="Z60-Ov-osn" firstAttribute="bottom" secondItem="R0e-ju-3rJ" secondAttribute="bottom" constant="-20" id="vpj-Rc-MBy"/>
207 <constraint firstAttribute="trailing" secondItem="7Md-pz-rS9" secondAttribute="trailing" constant="8" id="wn6-7R-Gny"/>
208 <constraint firstItem="OfR-lz-RdI" firstAttribute="leading" secondItem="ciF-HT-7im" secondAttribute="leading" id="yPd-vT-beo"/>
209 <constraint firstAttribute="height" constant="180" id="znJ-5h-UIP"/>
210 </constraints>
211 </view>
212 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="EK1-iD-A0q" userLabel="BootUpdate">
213 <rect key="frame" x="0.0" y="180" width="320" height="75"/>
214 <subviews>
215 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="起動設定" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JUj-0Q-xHq">
216 <rect key="frame" x="0.0" y="0.0" width="320" height="34"/>
217 <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
218 <constraints>
219 <constraint firstAttribute="height" constant="34" id="Olc-OO-SXW"/>
220 </constraints>
221 <fontDescription key="fontDescription" type="system" pointSize="17"/>
222 <nil key="textColor"/>
223 <nil key="highlightedColor"/>
224 </label>
225 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="起動設定" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FeW-R8-ZLg">
226 <rect key="frame" x="8" y="42" width="265" height="21"/>
227 <constraints>
228 <constraint firstAttribute="width" constant="265" id="kDe-OM-fwD"/>
229 </constraints>
230 <fontDescription key="fontDescription" type="system" pointSize="17"/>
231 <nil key="textColor"/>
232 <nil key="highlightedColor"/>
233 </label>
234 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Wet-HF-Lge">
235 <rect key="frame" x="281" y="37" width="31" height="30"/>
236 <state key="normal" title="変更"/>
237 <connections>
238 <action selector="bootUpdateClicked:" destination="-1" eventType="touchUpInside" id="0Jc-tk-ZAm"/>
239 </connections>
240 </button>
241 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BYM-dX-nl5">
242 <rect key="frame" x="118" y="42" width="142" height="21"/>
243 <constraints>
244 <constraint firstAttribute="width" constant="142" id="pFH-bf-nRV"/>
245 </constraints>
246 <fontDescription key="fontDescription" type="system" pointSize="17"/>
247 <nil key="textColor"/>
248 <nil key="highlightedColor"/>
249 </label>
250 </subviews>
251 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
252 <constraints>
253 <constraint firstAttribute="height" constant="75" id="54h-aI-Z7C"/>
254 <constraint firstItem="Wet-HF-Lge" firstAttribute="top" secondItem="JUj-0Q-xHq" secondAttribute="bottom" constant="3" id="6JT-RP-DCy"/>
255 <constraint firstItem="BYM-dX-nl5" firstAttribute="baseline" secondItem="FeW-R8-ZLg" secondAttribute="baseline" id="JOg-UI-yVM"/>
256 <constraint firstItem="FeW-R8-ZLg" firstAttribute="leading" secondItem="EK1-iD-A0q" secondAttribute="leading" constant="8" id="UK3-X2-P5Y"/>
257 <constraint firstAttribute="trailing" secondItem="JUj-0Q-xHq" secondAttribute="trailing" id="Z64-1m-uea"/>
258 <constraint firstItem="JUj-0Q-xHq" firstAttribute="leading" secondItem="EK1-iD-A0q" secondAttribute="leading" id="cZj-EX-Gfm"/>
259 <constraint firstItem="BYM-dX-nl5" firstAttribute="firstBaseline" secondItem="FeW-R8-ZLg" secondAttribute="baseline" id="hU3-6d-dJQ"/>
260 <constraint firstAttribute="trailing" secondItem="Wet-HF-Lge" secondAttribute="trailing" constant="8" id="qbG-VA-kWF"/>
261 <constraint firstItem="FeW-R8-ZLg" firstAttribute="top" secondItem="JUj-0Q-xHq" secondAttribute="bottom" constant="8" id="vWo-l9-9jD"/>
262 <constraint firstItem="Wet-HF-Lge" firstAttribute="leading" secondItem="BYM-dX-nl5" secondAttribute="trailing" constant="21" id="yDV-sa-sEI"/>
263 <constraint firstItem="JUj-0Q-xHq" firstAttribute="top" secondItem="EK1-iD-A0q" secondAttribute="top" id="yWX-7x-O3R"/>
264 </constraints>
265 </view>
266 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bZ6-5Z-llY" userLabel="Reset">
267 <rect key="frame" x="0.0" y="255" width="320" height="75"/>
268 <subviews>
269 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="再起動" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aoh-8d-4Hm">
270 <rect key="frame" x="0.0" y="0.0" width="320" height="34"/>
271 <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
272 <constraints>
273 <constraint firstAttribute="height" constant="34" id="5LF-W6-3RE"/>
274 </constraints>
275 <fontDescription key="fontDescription" type="system" pointSize="17"/>
276 <nil key="textColor"/>
277 <nil key="highlightedColor"/>
278 </label>
279 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="再起動" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KP3-TN-BE4">
280 <rect key="frame" x="8" y="42" width="265" height="21"/>
281 <constraints>
282 <constraint firstAttribute="width" constant="265" id="BaW-il-ETI"/>
283 </constraints>
284 <fontDescription key="fontDescription" type="system" pointSize="17"/>
285 <nil key="textColor"/>
286 <nil key="highlightedColor"/>
287 </label>
288 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="a9m-cI-xwT">
289 <rect key="frame" x="266" y="37" width="46" height="30"/>
290 <state key="normal" title="再起動"/>
291 <connections>
292 <action selector="resetClicked:" destination="-1" eventType="touchUpInside" id="219-ka-ROT"/>
293 </connections>
294 </button>
295 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EV7-GY-Xat">
296 <rect key="frame" x="103" y="42" width="142" height="21"/>
297 <constraints>
298 <constraint firstAttribute="width" constant="142" id="NlF-QB-ifc"/>
299 </constraints>
300 <fontDescription key="fontDescription" type="system" pointSize="17"/>
301 <nil key="textColor"/>
302 <nil key="highlightedColor"/>
303 </label>
304 </subviews>
305 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
306 <constraints>
307 <constraint firstItem="aoh-8d-4Hm" firstAttribute="leading" secondItem="bZ6-5Z-llY" secondAttribute="leading" id="3i4-jh-uBp"/>
308 <constraint firstAttribute="trailing" secondItem="aoh-8d-4Hm" secondAttribute="trailing" id="5kX-wX-BtU"/>
309 <constraint firstItem="a9m-cI-xwT" firstAttribute="top" secondItem="aoh-8d-4Hm" secondAttribute="bottom" constant="3" id="8Dt-UA-FxO"/>
310 <constraint firstItem="KP3-TN-BE4" firstAttribute="top" secondItem="aoh-8d-4Hm" secondAttribute="bottom" constant="8" id="AoI-Mp-wE1"/>
311 <constraint firstItem="EV7-GY-Xat" firstAttribute="baseline" secondItem="KP3-TN-BE4" secondAttribute="baseline" id="Qdx-Ec-9MF"/>
312 <constraint firstAttribute="height" constant="75" id="UZ8-qw-cam"/>
313 <constraint firstItem="EV7-GY-Xat" firstAttribute="firstBaseline" secondItem="KP3-TN-BE4" secondAttribute="baseline" id="WRh-Xu-687"/>
314 <constraint firstItem="aoh-8d-4Hm" firstAttribute="top" secondItem="bZ6-5Z-llY" secondAttribute="top" id="WcY-bv-6L2"/>
315 <constraint firstItem="KP3-TN-BE4" firstAttribute="leading" secondItem="bZ6-5Z-llY" secondAttribute="leading" constant="8" id="jcx-be-l7d"/>
316 <constraint firstItem="a9m-cI-xwT" firstAttribute="leading" secondItem="EV7-GY-Xat" secondAttribute="trailing" constant="21" id="ku9-58-nU2"/>
317 <constraint firstAttribute="trailing" secondItem="a9m-cI-xwT" secondAttribute="trailing" constant="8" id="sjl-Hd-7Op"/>
318 </constraints>
319 </view>
320 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="m7Q-v9-hms" userLabel="BootloaderReset">
321 <rect key="frame" x="0.0" y="330" width="320" height="75"/>
322 <subviews>
323 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="更新モード設定して再起動" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RE2-pA-egH">
324 <rect key="frame" x="0.0" y="0.0" width="320" height="34"/>
325 <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
326 <constraints>
327 <constraint firstAttribute="height" constant="34" id="mA3-g9-KLy"/>
328 </constraints>
329 <fontDescription key="fontDescription" type="system" pointSize="17"/>
330 <nil key="textColor"/>
331 <nil key="highlightedColor"/>
332 </label>
333 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="更新モード設定して再起動" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aRd-mf-2Ol">
334 <rect key="frame" x="8" y="42" width="265" height="21"/>
335 <constraints>
336 <constraint firstAttribute="width" constant="265" id="Ftu-cf-gZ7"/>
337 </constraints>
338 <fontDescription key="fontDescription" type="system" pointSize="17"/>
339 <nil key="textColor"/>
340 <nil key="highlightedColor"/>
341 </label>
342 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ygi-T6-jss">
343 <rect key="frame" x="266" y="37" width="46" height="30"/>
344 <state key="normal" title="再起動"/>
345 <connections>
346 <action selector="updateModeResetClicked:" destination="-1" eventType="touchUpInside" id="uW0-3Q-4q1"/>
347 </connections>
348 </button>
349 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jok-le-R5B">
350 <rect key="frame" x="103" y="42" width="142" height="21"/>
351 <constraints>
352 <constraint firstAttribute="width" constant="142" id="dH4-At-cGO"/>
353 </constraints>
354 <fontDescription key="fontDescription" type="system" pointSize="17"/>
355 <nil key="textColor"/>
356 <nil key="highlightedColor"/>
357 </label>
358 </subviews>
359 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
360 <constraints>
361 <constraint firstItem="RE2-pA-egH" firstAttribute="top" secondItem="m7Q-v9-hms" secondAttribute="top" id="2G8-F2-d5j"/>
362 <constraint firstItem="aRd-mf-2Ol" firstAttribute="top" secondItem="RE2-pA-egH" secondAttribute="bottom" constant="8" id="95a-gB-O3O"/>
363 <constraint firstAttribute="height" constant="75" id="FhP-RM-laU"/>
364 <constraint firstItem="Jok-le-R5B" firstAttribute="firstBaseline" secondItem="aRd-mf-2Ol" secondAttribute="baseline" id="P1g-2x-2FY"/>
365 <constraint firstItem="Jok-le-R5B" firstAttribute="baseline" secondItem="aRd-mf-2Ol" secondAttribute="baseline" id="PjK-gb-5Ue"/>
366 <constraint firstAttribute="trailing" secondItem="ygi-T6-jss" secondAttribute="trailing" constant="8" id="QHZ-9k-ogr"/>
367 <constraint firstItem="ygi-T6-jss" firstAttribute="top" secondItem="RE2-pA-egH" secondAttribute="bottom" constant="3" id="eN5-Ub-frP"/>
368 <constraint firstItem="ygi-T6-jss" firstAttribute="leading" secondItem="Jok-le-R5B" secondAttribute="trailing" constant="21" id="iqJ-SU-eC2"/>
369 <constraint firstItem="RE2-pA-egH" firstAttribute="leading" secondItem="m7Q-v9-hms" secondAttribute="leading" id="qrF-eN-6u1"/>
370 <constraint firstAttribute="trailing" secondItem="RE2-pA-egH" secondAttribute="trailing" id="vPV-i2-D7j"/>
371 <constraint firstItem="aRd-mf-2Ol" firstAttribute="leading" secondItem="m7Q-v9-hms" secondAttribute="leading" constant="8" id="zad-OF-EaU"/>
372 </constraints>
373 </view>
374 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a3E-ut-IxQ" userLabel="FirmwareDownload">
375 <rect key="frame" x="0.0" y="405" width="320" height="75"/>
376 <subviews>
377 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ファームウェア取得" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1ra-xe-iFB">
378 <rect key="frame" x="0.0" y="1" width="320" height="34"/>
379 <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
380 <constraints>
381 <constraint firstAttribute="height" constant="34" id="I4p-Q6-vPi"/>
382 </constraints>
383 <fontDescription key="fontDescription" type="system" pointSize="17"/>
384 <nil key="textColor"/>
385 <nil key="highlightedColor"/>
386 </label>
387 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ファームウェア取得" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vuJ-ex-WUe">
388 <rect key="frame" x="8" y="43" width="265" height="21"/>
389 <constraints>
390 <constraint firstAttribute="width" constant="265" id="imp-EA-ELf"/>
391 </constraints>
392 <fontDescription key="fontDescription" type="system" pointSize="17"/>
393 <nil key="textColor"/>
394 <nil key="highlightedColor"/>
395 </label>
396 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JZU-KM-0dc">
397 <rect key="frame" x="118" y="43" width="142" height="21"/>
398 <constraints>
399 <constraint firstAttribute="width" constant="142" id="s0p-Sy-t7Z"/>
400 </constraints>
401 <fontDescription key="fontDescription" type="system" pointSize="17"/>
402 <nil key="textColor"/>
403 <nil key="highlightedColor"/>
404 </label>
405 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rpM-I0-KKH">
406 <rect key="frame" x="281" y="38" width="31" height="30"/>
407 <state key="normal" title="取得"/>
408 <connections>
409 <action selector="firmwareDownloadClicked:" destination="-1" eventType="touchUpInside" id="IqB-mb-0Bj"/>
410 </connections>
411 </button>
412 </subviews>
413 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
414 <constraints>
415 <constraint firstAttribute="bottom" secondItem="rpM-I0-KKH" secondAttribute="bottom" constant="7" id="5Um-38-42k"/>
416 <constraint firstAttribute="trailing" secondItem="1ra-xe-iFB" secondAttribute="trailing" id="Dbo-LH-DFT"/>
417 <constraint firstAttribute="trailing" secondItem="rpM-I0-KKH" secondAttribute="trailing" constant="8" id="EAU-GK-PqN"/>
418 <constraint firstItem="1ra-xe-iFB" firstAttribute="leading" secondItem="a3E-ut-IxQ" secondAttribute="leading" id="Ogz-A5-raj"/>
419 <constraint firstItem="rpM-I0-KKH" firstAttribute="leading" secondItem="JZU-KM-0dc" secondAttribute="trailing" constant="21" id="eUG-X4-h3I"/>
420 <constraint firstItem="vuJ-ex-WUe" firstAttribute="top" secondItem="1ra-xe-iFB" secondAttribute="bottom" constant="8" id="kob-Hh-Y5b"/>
421 <constraint firstAttribute="height" constant="75" id="ksV-8F-g36"/>
422 <constraint firstItem="JZU-KM-0dc" firstAttribute="firstBaseline" secondItem="vuJ-ex-WUe" secondAttribute="baseline" id="ouR-4p-6Vu"/>
423 <constraint firstItem="rpM-I0-KKH" firstAttribute="centerY" secondItem="JZU-KM-0dc" secondAttribute="centerY" id="r5u-TZ-Re7"/>
424 <constraint firstItem="JZU-KM-0dc" firstAttribute="baseline" secondItem="vuJ-ex-WUe" secondAttribute="baseline" id="wtJ-jE-Ha8"/>
425 <constraint firstItem="vuJ-ex-WUe" firstAttribute="leading" secondItem="a3E-ut-IxQ" secondAttribute="leading" constant="8" id="ynI-Eo-7Y0"/>
426 </constraints>
427 </view>
428 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LIJ-gW-1dP" userLabel="FirmwareUpdate">
429 <rect key="frame" x="0.0" y="480" width="320" height="75"/>
430 <subviews>
431 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ファームウェア書込" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p1j-9l-PQF">
432 <rect key="frame" x="0.0" y="1" width="320" height="34"/>
433 <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
434 <constraints>
435 <constraint firstAttribute="height" constant="34" id="Z05-yb-XYI"/>
436 </constraints>
437 <fontDescription key="fontDescription" type="system" pointSize="17"/>
438 <nil key="textColor"/>
439 <nil key="highlightedColor"/>
440 </label>
441 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ファームウェア書込" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Mhd-pD-81B">
442 <rect key="frame" x="8" y="43" width="265" height="21"/>
443 <constraints>
444 <constraint firstAttribute="width" constant="265" id="MQV-xs-vFB"/>
445 </constraints>
446 <fontDescription key="fontDescription" type="system" pointSize="17"/>
447 <nil key="textColor"/>
448 <nil key="highlightedColor"/>
449 </label>
450 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vcs-sE-ZYp">
451 <rect key="frame" x="118" y="43" width="142" height="21"/>
452 <constraints>
453 <constraint firstAttribute="width" constant="142" id="cgn-De-giJ"/>
454 </constraints>
455 <fontDescription key="fontDescription" type="system" pointSize="17"/>
456 <nil key="textColor"/>
457 <nil key="highlightedColor"/>
458 </label>
459 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XEG-Eo-a4N">
460 <rect key="frame" x="281" y="38" width="31" height="30"/>
461 <state key="normal" title="書込"/>
462 <connections>
463 <action selector="firmwareUpdateClicked:" destination="-1" eventType="touchUpInside" id="S36-5x-G2y"/>
464 </connections>
465 </button>
466 </subviews>
467 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
468 <constraints>
469 <constraint firstAttribute="trailing" secondItem="XEG-Eo-a4N" secondAttribute="trailing" constant="8" id="63U-E0-9Bo"/>
470 <constraint firstItem="p1j-9l-PQF" firstAttribute="leading" secondItem="LIJ-gW-1dP" secondAttribute="leading" id="Lrb-Nr-YLq"/>
471 <constraint firstItem="Vcs-sE-ZYp" firstAttribute="firstBaseline" secondItem="Mhd-pD-81B" secondAttribute="baseline" id="UgP-c3-uDZ"/>
472 <constraint firstAttribute="bottom" secondItem="XEG-Eo-a4N" secondAttribute="bottom" constant="7" id="aBm-fB-qcP"/>
473 <constraint firstItem="Vcs-sE-ZYp" firstAttribute="baseline" secondItem="Mhd-pD-81B" secondAttribute="baseline" id="hPd-Ov-62R"/>
474 <constraint firstAttribute="height" constant="75" id="ian-h3-SoG"/>
475 <constraint firstItem="Mhd-pD-81B" firstAttribute="top" secondItem="p1j-9l-PQF" secondAttribute="bottom" constant="8" id="m4l-jb-sFs"/>
476 <constraint firstAttribute="trailing" secondItem="p1j-9l-PQF" secondAttribute="trailing" id="noU-qy-By3"/>
477 <constraint firstItem="XEG-Eo-a4N" firstAttribute="centerY" secondItem="Vcs-sE-ZYp" secondAttribute="centerY" id="pkS-Gh-Vye"/>
478 <constraint firstItem="Mhd-pD-81B" firstAttribute="leading" secondItem="LIJ-gW-1dP" secondAttribute="leading" constant="8" id="slX-9B-9u2"/>
479 <constraint firstItem="XEG-Eo-a4N" firstAttribute="leading" secondItem="Vcs-sE-ZYp" secondAttribute="trailing" constant="21" id="vlB-7y-R0M"/>
480 </constraints>
481 </view>
482 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bks-QW-Uu4" userLabel="EepromWrite">
483 <rect key="frame" x="0.0" y="555" width="320" height="75"/>
484 <subviews>
485 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="EEPROMデータ更新" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nwH-ab-Yjr">
486 <rect key="frame" x="0.0" y="1" width="320" height="34"/>
487 <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
488 <constraints>
489 <constraint firstAttribute="height" constant="34" id="Hx7-sv-mUy"/>
490 </constraints>
491 <fontDescription key="fontDescription" type="system" pointSize="17"/>
492 <nil key="textColor"/>
493 <nil key="highlightedColor"/>
494 </label>
495 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="EEPROMデータ更新" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mMc-Wd-fEe">
496 <rect key="frame" x="8" y="43" width="265" height="21"/>
497 <constraints>
498 <constraint firstAttribute="width" constant="265" id="bb4-jC-ce7"/>
499 </constraints>
500 <fontDescription key="fontDescription" type="system" pointSize="17"/>
501 <nil key="textColor"/>
502 <nil key="highlightedColor"/>
503 </label>
504 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="MD4-kn-fyo">
505 <rect key="frame" x="118" y="43" width="142" height="21"/>
506 <constraints>
507 <constraint firstAttribute="width" constant="142" id="cgl-hU-Eov"/>
508 </constraints>
509 <fontDescription key="fontDescription" type="system" pointSize="17"/>
510 <nil key="textColor"/>
511 <nil key="highlightedColor"/>
512 </label>
513 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dHq-3b-ofO">
514 <rect key="frame" x="281" y="38" width="31" height="30"/>
515 <state key="normal" title="変更"/>
516 <connections>
517 <action selector="eepromUpdateClicked:" destination="-1" eventType="touchUpInside" id="Q7x-Qp-WoP"/>
518 </connections>
519 </button>
520 </subviews>
521 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
522 <constraints>
523 <constraint firstItem="dHq-3b-ofO" firstAttribute="centerY" secondItem="MD4-kn-fyo" secondAttribute="centerY" id="0Pf-Nj-gpn"/>
524 <constraint firstItem="nwH-ab-Yjr" firstAttribute="leading" secondItem="bks-QW-Uu4" secondAttribute="leading" id="I1v-Oc-1Lq"/>
525 <constraint firstAttribute="height" constant="75" id="Ief-OF-WTE"/>
526 <constraint firstAttribute="trailing" secondItem="nwH-ab-Yjr" secondAttribute="trailing" id="VTS-lT-vAy"/>
527 <constraint firstItem="dHq-3b-ofO" firstAttribute="leading" secondItem="MD4-kn-fyo" secondAttribute="trailing" constant="21" id="auM-hU-6D6"/>
528 <constraint firstAttribute="trailing" secondItem="dHq-3b-ofO" secondAttribute="trailing" constant="8" id="fIk-98-4vr"/>
529 <constraint firstItem="MD4-kn-fyo" firstAttribute="baseline" secondItem="mMc-Wd-fEe" secondAttribute="baseline" id="mhH-ON-yLC"/>
530 <constraint firstItem="mMc-Wd-fEe" firstAttribute="leading" secondItem="bks-QW-Uu4" secondAttribute="leading" constant="8" id="nZg-Es-OKc"/>
531 <constraint firstItem="MD4-kn-fyo" firstAttribute="firstBaseline" secondItem="mMc-Wd-fEe" secondAttribute="baseline" id="phN-VD-Dkl"/>
532 <constraint firstItem="mMc-Wd-fEe" firstAttribute="top" secondItem="nwH-ab-Yjr" secondAttribute="bottom" constant="8" id="x1L-Xq-4Vh"/>
533 <constraint firstAttribute="bottom" secondItem="dHq-3b-ofO" secondAttribute="bottom" constant="7" id="zvO-EU-8nY"/>
534 </constraints>
535 </view>
536 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zdW-Jd-NbE" userLabel="Motor">
537 <rect key="frame" x="0.0" y="630" width="320" height="75"/>
538 <subviews>
539 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="モーター" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="j2Q-yU-L06">
540 <rect key="frame" x="0.0" y="1" width="320" height="34"/>
541 <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
542 <constraints>
543 <constraint firstAttribute="height" constant="34" id="gcr-hn-ziN"/>
544 </constraints>
545 <fontDescription key="fontDescription" type="system" pointSize="17"/>
546 <nil key="textColor"/>
547 <nil key="highlightedColor"/>
548 </label>
549 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="モーター" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hCE-9A-2PM">
550 <rect key="frame" x="8" y="43" width="265" height="21"/>
551 <constraints>
552 <constraint firstAttribute="width" constant="265" id="HuV-m2-3Xu"/>
553 </constraints>
554 <fontDescription key="fontDescription" type="system" pointSize="17"/>
555 <nil key="textColor"/>
556 <nil key="highlightedColor"/>
557 </label>
558 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YT7-Nh-qYQ">
559 <rect key="frame" x="118" y="43" width="142" height="21"/>
560 <constraints>
561 <constraint firstAttribute="width" constant="142" id="dOe-fy-Ux7"/>
562 </constraints>
563 <fontDescription key="fontDescription" type="system" pointSize="17"/>
564 <nil key="textColor"/>
565 <nil key="highlightedColor"/>
566 </label>
567 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4SC-vA-ehC">
568 <rect key="frame" x="281" y="38" width="31" height="30"/>
569 <state key="normal" title="変更"/>
570 <connections>
571 <action selector="InputMotorClicked:" destination="-1" eventType="touchUpInside" id="wh2-Uv-UY0"/>
572 </connections>
573 </button>
574 </subviews>
575 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
576 <constraints>
577 <constraint firstAttribute="bottom" secondItem="4SC-vA-ehC" secondAttribute="bottom" constant="7" id="04P-RN-D5m"/>
578 <constraint firstItem="j2Q-yU-L06" firstAttribute="leading" secondItem="zdW-Jd-NbE" secondAttribute="leading" id="3Xv-QV-hgG"/>
579 <constraint firstItem="hCE-9A-2PM" firstAttribute="top" secondItem="j2Q-yU-L06" secondAttribute="bottom" constant="8" id="BDI-DS-WrK"/>
580 <constraint firstItem="YT7-Nh-qYQ" firstAttribute="baseline" secondItem="hCE-9A-2PM" secondAttribute="baseline" id="Bcx-oL-NGv"/>
581 <constraint firstAttribute="height" constant="75" id="LDC-QK-fUB"/>
582 <constraint firstItem="4SC-vA-ehC" firstAttribute="leading" secondItem="YT7-Nh-qYQ" secondAttribute="trailing" constant="21" id="RI3-rD-2OQ"/>
583 <constraint firstAttribute="trailing" secondItem="j2Q-yU-L06" secondAttribute="trailing" id="UwX-WW-zYM"/>
584 <constraint firstItem="YT7-Nh-qYQ" firstAttribute="firstBaseline" secondItem="hCE-9A-2PM" secondAttribute="baseline" id="hrG-SH-9Fw"/>
585 <constraint firstItem="4SC-vA-ehC" firstAttribute="centerY" secondItem="YT7-Nh-qYQ" secondAttribute="centerY" id="joW-nu-MMi"/>
586 <constraint firstAttribute="trailing" secondItem="4SC-vA-ehC" secondAttribute="trailing" constant="8" id="ndm-P5-t61"/>
587 <constraint firstItem="hCE-9A-2PM" firstAttribute="leading" secondItem="zdW-Jd-NbE" secondAttribute="leading" constant="8" id="x5o-BG-MEI"/>
588 </constraints>
589 </view>
590 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qtP-5j-EqG" userLabel="Sound">
591 <rect key="frame" x="0.0" y="705" width="320" height="75"/>
592 <subviews>
593 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="サウンド" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Hb0-mJ-MpB">
594 <rect key="frame" x="0.0" y="1" width="320" height="34"/>
595 <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
596 <constraints>
597 <constraint firstAttribute="height" constant="34" id="KyR-of-NVe"/>
598 </constraints>
599 <fontDescription key="fontDescription" type="system" pointSize="17"/>
600 <nil key="textColor"/>
601 <nil key="highlightedColor"/>
602 </label>
603 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="サウンド" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="i7x-yH-7jw">
604 <rect key="frame" x="8" y="43" width="265" height="21"/>
605 <constraints>
606 <constraint firstAttribute="width" constant="265" id="P85-8S-pXh"/>
607 </constraints>
608 <fontDescription key="fontDescription" type="system" pointSize="17"/>
609 <nil key="textColor"/>
610 <nil key="highlightedColor"/>
611 </label>
612 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wb2-fb-a4B">
613 <rect key="frame" x="118" y="43" width="142" height="21"/>
614 <constraints>
615 <constraint firstAttribute="width" constant="142" id="A2X-Wy-a6P"/>
616 </constraints>
617 <fontDescription key="fontDescription" type="system" pointSize="17"/>
618 <nil key="textColor"/>
619 <nil key="highlightedColor"/>
620 </label>
621 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bg3-Bd-fvo">
622 <rect key="frame" x="281" y="38" width="31" height="30"/>
623 <state key="normal" title="変更"/>
624 <connections>
625 <action selector="InputSoundClicked:" destination="-1" eventType="touchUpInside" id="vBM-jo-UKX"/>
626 </connections>
627 </button>
628 </subviews>
629 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
630 <constraints>
631 <constraint firstItem="Wb2-fb-a4B" firstAttribute="firstBaseline" secondItem="i7x-yH-7jw" secondAttribute="baseline" id="1oo-ae-rhS"/>
632 <constraint firstAttribute="trailing" secondItem="bg3-Bd-fvo" secondAttribute="trailing" constant="8" id="6gw-Qe-zoC"/>
633 <constraint firstAttribute="height" constant="75" id="Aan-7k-u8h"/>
634 <constraint firstItem="Wb2-fb-a4B" firstAttribute="baseline" secondItem="i7x-yH-7jw" secondAttribute="baseline" id="Ibi-oo-0uU"/>
635 <constraint firstItem="bg3-Bd-fvo" firstAttribute="leading" secondItem="Wb2-fb-a4B" secondAttribute="trailing" constant="21" id="K1B-xx-asU"/>
636 <constraint firstItem="i7x-yH-7jw" firstAttribute="leading" secondItem="qtP-5j-EqG" secondAttribute="leading" constant="8" id="PiM-bp-DHF"/>
637 <constraint firstItem="Hb0-mJ-MpB" firstAttribute="leading" secondItem="qtP-5j-EqG" secondAttribute="leading" id="SYt-Tq-FaX"/>
638 <constraint firstAttribute="bottom" secondItem="bg3-Bd-fvo" secondAttribute="bottom" constant="7" id="bRJ-MP-vpO"/>
639 <constraint firstAttribute="trailing" secondItem="Hb0-mJ-MpB" secondAttribute="trailing" id="egv-cE-MA8"/>
640 <constraint firstItem="bg3-Bd-fvo" firstAttribute="centerY" secondItem="Wb2-fb-a4B" secondAttribute="centerY" id="s4y-EG-GLo"/>
641 <constraint firstItem="i7x-yH-7jw" firstAttribute="top" secondItem="Hb0-mJ-MpB" secondAttribute="bottom" constant="8" id="z90-rN-nsu"/>
642 </constraints>
643 </view>
644 </subviews>
645 <constraints>
646 <constraint firstItem="m7Q-v9-hms" firstAttribute="leading" secondItem="bZ6-5Z-llY" secondAttribute="leading" id="0C5-GP-1r9"/>
647 <constraint firstItem="zdW-Jd-NbE" firstAttribute="top" secondItem="bks-QW-Uu4" secondAttribute="bottom" id="0Sw-Gw-loS"/>
648 <constraint firstItem="EK1-iD-A0q" firstAttribute="top" secondItem="eIE-UX-Coo" secondAttribute="bottom" id="5IN-lS-ik5"/>
649 <constraint firstAttribute="trailing" secondItem="LIJ-gW-1dP" secondAttribute="trailing" id="60O-2b-ZdC"/>
650 <constraint firstItem="bZ6-5Z-llY" firstAttribute="trailing" secondItem="EK1-iD-A0q" secondAttribute="trailing" id="7HO-B6-6Or"/>
651 <constraint firstAttribute="height" constant="780" id="8c9-cl-D0b"/>
652 <constraint firstItem="a3E-ut-IxQ" firstAttribute="top" secondItem="m7Q-v9-hms" secondAttribute="bottom" id="9om-H3-469"/>
653 <constraint firstItem="qtP-5j-EqG" firstAttribute="leading" secondItem="zdW-Jd-NbE" secondAttribute="leading" id="Bf4-Yj-asS"/>
654 <constraint firstItem="zdW-Jd-NbE" firstAttribute="leading" secondItem="bks-QW-Uu4" secondAttribute="leading" id="ExU-yM-9Vb"/>
655 <constraint firstItem="qtP-5j-EqG" firstAttribute="trailing" secondItem="zdW-Jd-NbE" secondAttribute="trailing" id="FzY-aC-VYM"/>
656 <constraint firstItem="bZ6-5Z-llY" firstAttribute="top" secondItem="EK1-iD-A0q" secondAttribute="bottom" id="G3H-PW-uTb"/>
657 <constraint firstItem="bks-QW-Uu4" firstAttribute="trailing" secondItem="LIJ-gW-1dP" secondAttribute="trailing" id="G4e-9d-qvR"/>
658 <constraint firstItem="EK1-iD-A0q" firstAttribute="leading" secondItem="LIJ-gW-1dP" secondAttribute="leading" id="H7u-NR-BJO"/>
659 <constraint firstItem="LIJ-gW-1dP" firstAttribute="top" secondItem="a3E-ut-IxQ" secondAttribute="bottom" id="HNY-y6-piQ"/>
660 <constraint firstItem="eIE-UX-Coo" firstAttribute="trailing" secondItem="EK1-iD-A0q" secondAttribute="trailing" id="Ic5-mD-bYI"/>
661 <constraint firstItem="zdW-Jd-NbE" firstAttribute="trailing" secondItem="bks-QW-Uu4" secondAttribute="trailing" id="J3z-oH-cvq"/>
662 <constraint firstItem="bks-QW-Uu4" firstAttribute="leading" secondItem="LIJ-gW-1dP" secondAttribute="leading" id="MId-bN-m0y"/>
663 <constraint firstItem="eIE-UX-Coo" firstAttribute="top" secondItem="uMf-cM-5yr" secondAttribute="top" id="Wh6-3J-zbe"/>
664 <constraint firstItem="LIJ-gW-1dP" firstAttribute="leading" secondItem="uMf-cM-5yr" secondAttribute="leading" id="b4y-4b-BWL"/>
665 <constraint firstItem="qtP-5j-EqG" firstAttribute="top" secondItem="zdW-Jd-NbE" secondAttribute="bottom" id="fyK-F2-Jtx"/>
666 <constraint firstItem="a3E-ut-IxQ" firstAttribute="trailing" secondItem="bZ6-5Z-llY" secondAttribute="trailing" id="gou-vb-Vap"/>
667 <constraint firstItem="EK1-iD-A0q" firstAttribute="trailing" secondItem="LIJ-gW-1dP" secondAttribute="trailing" id="hf9-VU-4Zs"/>
668 <constraint firstItem="m7Q-v9-hms" firstAttribute="top" secondItem="bZ6-5Z-llY" secondAttribute="bottom" id="n5l-FV-o0j"/>
669 <constraint firstItem="a3E-ut-IxQ" firstAttribute="leading" secondItem="bZ6-5Z-llY" secondAttribute="leading" id="qbu-mP-GU7"/>
670 <constraint firstItem="bZ6-5Z-llY" firstAttribute="leading" secondItem="EK1-iD-A0q" secondAttribute="leading" id="vX5-pX-GB4"/>
671 <constraint firstItem="eIE-UX-Coo" firstAttribute="leading" secondItem="EK1-iD-A0q" secondAttribute="leading" id="w9S-vr-m4X"/>
672 <constraint firstItem="m7Q-v9-hms" firstAttribute="trailing" secondItem="bZ6-5Z-llY" secondAttribute="trailing" id="wyc-lV-7Wh"/>
673 <constraint firstItem="bks-QW-Uu4" firstAttribute="top" secondItem="LIJ-gW-1dP" secondAttribute="bottom" id="xir-Bz-6Ku"/>
674 </constraints>
675 <point key="canvasLocation" x="-470" y="2748"/>
676 </view>
677 </objects>
678 </document>
1 // !$*UTF8*$!
2 {
3 archiveVersion = 1;
4 classes = {
5 };
6 objectVersion = 46;
7 objects = {
8
9 /* Begin PBXBuildFile section */
10 4466131E1E134FC000A56C82 /* SettingsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 446613181E134FC000A56C82 /* SettingsController.m */; };
11 4466131F1E134FC000A56C82 /* SettingsController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 446613191E134FC000A56C82 /* SettingsController.xib */; };
12 CB34DA271E5E9C2200EBA2E4 /* InputMotorController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CB34DA261E5E9C2200EBA2E4 /* InputMotorController.xib */; };
13 CB34DA2A1E5E9C4B00EBA2E4 /* InputMotorController.m in Sources */ = {isa = PBXBuildFile; fileRef = CB34DA291E5E9C4B00EBA2E4 /* InputMotorController.m */; };
14 CB53F4571F871AF300970458 /* InputSoundController.m in Sources */ = {isa = PBXBuildFile; fileRef = CB53F4551F871AF300970458 /* InputSoundController.m */; };
15 CB53F4581F871AF300970458 /* InputSoundController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CB53F4561F871AF300970458 /* InputSoundController.xib */; };
16 CBE0DBC71F25804D00E765A4 /* EepromController.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE0DBC51F25804D00E765A4 /* EepromController.m */; };
17 CBE0DBC81F25804D00E765A4 /* EepromController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CBE0DBC61F25804D00E765A4 /* EepromController.xib */; };
18 CBE0DBCC1F258A4000E765A4 /* EepromTemplateController.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE0DBCA1F258A4000E765A4 /* EepromTemplateController.m */; };
19 CBE0DBCD1F258A4000E765A4 /* EepromTemplateController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CBE0DBCB1F258A4000E765A4 /* EepromTemplateController.xib */; };
20 CBE0DBD11F258A7400E765A4 /* EepromTemplateTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE0DBCF1F258A7400E765A4 /* EepromTemplateTableViewCell.m */; };
21 CBE0DBD21F258A7400E765A4 /* EepromTemplateTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = CBE0DBD01F258A7400E765A4 /* EepromTemplateTableViewCell.xib */; };
22 CBE0DBD61F25DDE600E765A4 /* BootSettingController.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE0DBD41F25DDE600E765A4 /* BootSettingController.m */; };
23 CBE0DBD71F25DDE600E765A4 /* BootSettingController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CBE0DBD51F25DDE600E765A4 /* BootSettingController.xib */; };
24 CBE48CC51CD07F0A0089DAF2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE48CC41CD07F0A0089DAF2 /* main.m */; };
25 CBE48CC81CD07F0A0089DAF2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE48CC71CD07F0A0089DAF2 /* AppDelegate.m */; };
26 CBE48CCB1CD07F0A0089DAF2 /* BleSearchViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE48CCA1CD07F0A0089DAF2 /* BleSearchViewController.m */; };
27 CBE48CCE1CD07F0A0089DAF2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CBE48CCC1CD07F0A0089DAF2 /* Main.storyboard */; };
28 CBE48CD01CD07F0A0089DAF2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CBE48CCF1CD07F0A0089DAF2 /* Assets.xcassets */; };
29 CBE48CD31CD07F0A0089DAF2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CBE48CD11CD07F0A0089DAF2 /* LaunchScreen.storyboard */; };
30 CBE48CDB1CD080120089DAF2 /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBE48CDA1CD080120089DAF2 /* CoreBluetooth.framework */; };
31 CBE48CE11CD084740089DAF2 /* BLE.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE48CDF1CD084740089DAF2 /* BLE.m */; };
32 CBE48CF81CD0B3C30089DAF2 /* BleProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE48CF71CD0B3C30089DAF2 /* BleProtocol.m */; };
33 CBE48D001CD0B6AA0089DAF2 /* BleControl.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE48CFF1CD0B6AA0089DAF2 /* BleControl.m */; };
34 CBE6440B1F30614800664E68 /* BleSearchResultTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE644081F30614800664E68 /* BleSearchResultTableViewCell.m */; };
35 CBE6440C1F30614800664E68 /* BleSearchResultTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE6440A1F30614800664E68 /* BleSearchResultTableViewController.m */; };
36 CBF4AEF41EE54D910029CE7D /* FirmwareUpdateController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CBF4AEF31EE54D910029CE7D /* FirmwareUpdateController.xib */; };
37 CBF4AEF71EE54DE10029CE7D /* FirmwareUpdateController.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AEF61EE54DE10029CE7D /* FirmwareUpdateController.m */; };
38 CBF4AF071EE55B620029CE7D /* AFHTTPSessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AEFB1EE55B620029CE7D /* AFHTTPSessionManager.m */; };
39 CBF4AF081EE55B620029CE7D /* AFNetworkReachabilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AEFE1EE55B620029CE7D /* AFNetworkReachabilityManager.m */; };
40 CBF4AF091EE55B620029CE7D /* AFSecurityPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AF001EE55B620029CE7D /* AFSecurityPolicy.m */; };
41 CBF4AF0A1EE55B620029CE7D /* AFURLRequestSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AF021EE55B620029CE7D /* AFURLRequestSerialization.m */; };
42 CBF4AF0B1EE55B620029CE7D /* AFURLResponseSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AF041EE55B620029CE7D /* AFURLResponseSerialization.m */; };
43 CBF4AF0C1EE55B620029CE7D /* AFURLSessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AF061EE55B620029CE7D /* AFURLSessionManager.m */; };
44 CBF4AF101EE637830029CE7D /* Operation.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AF0F1EE637830029CE7D /* Operation.m */; };
45 CBF4AF161EE667B70029CE7D /* FirmwareDownloadController.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AF141EE667B70029CE7D /* FirmwareDownloadController.m */; };
46 CBF4AF171EE667B70029CE7D /* FirmwareDownloadController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CBF4AF151EE667B70029CE7D /* FirmwareDownloadController.xib */; };
47 CBF4AF1B1EE667CA0029CE7D /* FirmwareWriteController.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AF191EE667CA0029CE7D /* FirmwareWriteController.m */; };
48 CBF4AF1C1EE667CA0029CE7D /* FirmwareWriteController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CBF4AF1A1EE667CA0029CE7D /* FirmwareWriteController.xib */; };
49 CBF4AF251EE670650029CE7D /* FirmwareDownloadControllerTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AF231EE670650029CE7D /* FirmwareDownloadControllerTableViewCell.m */; };
50 CBF4AF261EE670650029CE7D /* FirmwareDownloadControllerTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = CBF4AF241EE670650029CE7D /* FirmwareDownloadControllerTableViewCell.xib */; };
51 CBF4AF2B1EE6AD660029CE7D /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CBF4AF2A1EE6AD660029CE7D /* libsqlite3.dylib */; };
52 CBF4AF391EE6F1F80029CE7D /* DBManager.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AF381EE6F1F80029CE7D /* DBManager.m */; };
53 CBF4AF3D1EE7C8F00029CE7D /* FirmwareWriteControllerTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AF3B1EE7C8F00029CE7D /* FirmwareWriteControllerTableViewCell.m */; };
54 CBF4AF3E1EE7C8F00029CE7D /* FirmwareWriteControllerTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = CBF4AF3C1EE7C8F00029CE7D /* FirmwareWriteControllerTableViewCell.xib */; };
55 CBF4AF411EE7EE290029CE7D /* NSData+NSString.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4AF401EE7EE290029CE7D /* NSData+NSString.m */; };
56 CE3077271F8E289100EB87FF /* DemoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3077261F8E289100EB87FF /* DemoView.swift */; };
57 CE30772A1F8E2BD700EB87FF /* SenserData.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3077291F8E2BD700EB87FF /* SenserData.swift */; };
58 CE30772D1F8E36BD00EB87FF /* UserNofitication.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE30772C1F8E36BD00EB87FF /* UserNofitication.swift */; };
59 CE30772F1F8E36E500EB87FF /* UNResponseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE30772E1F8E36E500EB87FF /* UNResponseManager.swift */; };
60 CE3077311F8E37DA00EB87FF /* Caller.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3077301F8E37DA00EB87FF /* Caller.swift */; };
61 /* End PBXBuildFile section */
62
63 /* Begin PBXFileReference section */
64 446613171E134FC000A56C82 /* SettingsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsController.h; sourceTree = "<group>"; };
65 446613181E134FC000A56C82 /* SettingsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsController.m; sourceTree = "<group>"; };
66 446613191E134FC000A56C82 /* SettingsController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsController.xib; sourceTree = "<group>"; };
67 CB34DA261E5E9C2200EBA2E4 /* InputMotorController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = InputMotorController.xib; sourceTree = "<group>"; };
68 CB34DA281E5E9C4B00EBA2E4 /* InputMotorController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputMotorController.h; sourceTree = "<group>"; };
69 CB34DA291E5E9C4B00EBA2E4 /* InputMotorController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InputMotorController.m; sourceTree = "<group>"; };
70 CB53F4541F871AF300970458 /* InputSoundController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InputSoundController.h; sourceTree = "<group>"; };
71 CB53F4551F871AF300970458 /* InputSoundController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InputSoundController.m; sourceTree = "<group>"; };
72 CB53F4561F871AF300970458 /* InputSoundController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = InputSoundController.xib; sourceTree = "<group>"; };
73 CBE0DBC41F25804D00E765A4 /* EepromController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EepromController.h; sourceTree = "<group>"; };
74 CBE0DBC51F25804D00E765A4 /* EepromController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EepromController.m; sourceTree = "<group>"; };
75 CBE0DBC61F25804D00E765A4 /* EepromController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EepromController.xib; sourceTree = "<group>"; };
76 CBE0DBC91F258A4000E765A4 /* EepromTemplateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EepromTemplateController.h; sourceTree = "<group>"; };
77 CBE0DBCA1F258A4000E765A4 /* EepromTemplateController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EepromTemplateController.m; sourceTree = "<group>"; };
78 CBE0DBCB1F258A4000E765A4 /* EepromTemplateController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EepromTemplateController.xib; sourceTree = "<group>"; };
79 CBE0DBCE1F258A7400E765A4 /* EepromTemplateTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EepromTemplateTableViewCell.h; sourceTree = "<group>"; };
80 CBE0DBCF1F258A7400E765A4 /* EepromTemplateTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EepromTemplateTableViewCell.m; sourceTree = "<group>"; };
81 CBE0DBD01F258A7400E765A4 /* EepromTemplateTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EepromTemplateTableViewCell.xib; sourceTree = "<group>"; };
82 CBE0DBD31F25DDE600E765A4 /* BootSettingController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BootSettingController.h; sourceTree = "<group>"; };
83 CBE0DBD41F25DDE600E765A4 /* BootSettingController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BootSettingController.m; sourceTree = "<group>"; };
84 CBE0DBD51F25DDE600E765A4 /* BootSettingController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BootSettingController.xib; sourceTree = "<group>"; };
85 CBE48CC01CD07F0A0089DAF2 /* jacket_test_ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = jacket_test_ios.app; sourceTree = BUILT_PRODUCTS_DIR; };
86 CBE48CC41CD07F0A0089DAF2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
87 CBE48CC61CD07F0A0089DAF2 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
88 CBE48CC71CD07F0A0089DAF2 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
89 CBE48CC91CD07F0A0089DAF2 /* BleSearchViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BleSearchViewController.h; sourceTree = "<group>"; };
90 CBE48CCA1CD07F0A0089DAF2 /* BleSearchViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BleSearchViewController.m; sourceTree = "<group>"; };
91 CBE48CCD1CD07F0A0089DAF2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
92 CBE48CCF1CD07F0A0089DAF2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
93 CBE48CD21CD07F0A0089DAF2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
94 CBE48CD41CD07F0A0089DAF2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
95 CBE48CDA1CD080120089DAF2 /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; };
96 CBE48CDE1CD084740089DAF2 /* BLE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLE.h; sourceTree = "<group>"; };
97 CBE48CDF1CD084740089DAF2 /* BLE.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BLE.m; sourceTree = "<group>"; };
98 CBE48CE01CD084740089DAF2 /* BLEDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLEDefines.h; sourceTree = "<group>"; };
99 CBE48CF71CD0B3C30089DAF2 /* BleProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BleProtocol.m; sourceTree = "<group>"; };
100 CBE48CF91CD0B3D50089DAF2 /* BleProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BleProtocol.h; sourceTree = "<group>"; };
101 CBE48CFE1CD0B6AA0089DAF2 /* BleControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BleControl.h; sourceTree = "<group>"; };
102 CBE48CFF1CD0B6AA0089DAF2 /* BleControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BleControl.m; sourceTree = "<group>"; };
103 CBE644071F30614800664E68 /* BleSearchResultTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BleSearchResultTableViewCell.h; sourceTree = "<group>"; };
104 CBE644081F30614800664E68 /* BleSearchResultTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BleSearchResultTableViewCell.m; sourceTree = "<group>"; };
105 CBE644091F30614800664E68 /* BleSearchResultTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BleSearchResultTableViewController.h; sourceTree = "<group>"; };
106 CBE6440A1F30614800664E68 /* BleSearchResultTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BleSearchResultTableViewController.m; sourceTree = "<group>"; };
107 CBF4AEF31EE54D910029CE7D /* FirmwareUpdateController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FirmwareUpdateController.xib; sourceTree = "<group>"; };
108 CBF4AEF51EE54DE10029CE7D /* FirmwareUpdateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FirmwareUpdateController.h; sourceTree = "<group>"; };
109 CBF4AEF61EE54DE10029CE7D /* FirmwareUpdateController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirmwareUpdateController.m; sourceTree = "<group>"; };
110 CBF4AEFA1EE55B620029CE7D /* AFHTTPSessionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFHTTPSessionManager.h; sourceTree = "<group>"; };
111 CBF4AEFB1EE55B620029CE7D /* AFHTTPSessionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFHTTPSessionManager.m; sourceTree = "<group>"; };
112 CBF4AEFC1EE55B620029CE7D /* AFNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFNetworking.h; sourceTree = "<group>"; };
113 CBF4AEFD1EE55B620029CE7D /* AFNetworkReachabilityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFNetworkReachabilityManager.h; sourceTree = "<group>"; };
114 CBF4AEFE1EE55B620029CE7D /* AFNetworkReachabilityManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFNetworkReachabilityManager.m; sourceTree = "<group>"; };
115 CBF4AEFF1EE55B620029CE7D /* AFSecurityPolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFSecurityPolicy.h; sourceTree = "<group>"; };
116 CBF4AF001EE55B620029CE7D /* AFSecurityPolicy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFSecurityPolicy.m; sourceTree = "<group>"; };
117 CBF4AF011EE55B620029CE7D /* AFURLRequestSerialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFURLRequestSerialization.h; sourceTree = "<group>"; };
118 CBF4AF021EE55B620029CE7D /* AFURLRequestSerialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFURLRequestSerialization.m; sourceTree = "<group>"; };
119 CBF4AF031EE55B620029CE7D /* AFURLResponseSerialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFURLResponseSerialization.h; sourceTree = "<group>"; };
120 CBF4AF041EE55B620029CE7D /* AFURLResponseSerialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFURLResponseSerialization.m; sourceTree = "<group>"; };
121 CBF4AF051EE55B620029CE7D /* AFURLSessionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFURLSessionManager.h; sourceTree = "<group>"; };
122 CBF4AF061EE55B620029CE7D /* AFURLSessionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFURLSessionManager.m; sourceTree = "<group>"; };
123 CBF4AF0E1EE637830029CE7D /* Operation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Operation.h; path = Operation/Operation.h; sourceTree = SOURCE_ROOT; };
124 CBF4AF0F1EE637830029CE7D /* Operation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Operation.m; path = Operation/Operation.m; sourceTree = SOURCE_ROOT; };
125 CBF4AF121EE6389C0029CE7D /* jacket_test_ios_prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = jacket_test_ios_prefix.pch; sourceTree = SOURCE_ROOT; };
126 CBF4AF131EE667B70029CE7D /* FirmwareDownloadController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FirmwareDownloadController.h; sourceTree = "<group>"; };
127 CBF4AF141EE667B70029CE7D /* FirmwareDownloadController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirmwareDownloadController.m; sourceTree = "<group>"; };
128 CBF4AF151EE667B70029CE7D /* FirmwareDownloadController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FirmwareDownloadController.xib; sourceTree = "<group>"; };
129 CBF4AF181EE667CA0029CE7D /* FirmwareWriteController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FirmwareWriteController.h; sourceTree = "<group>"; };
130 CBF4AF191EE667CA0029CE7D /* FirmwareWriteController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirmwareWriteController.m; sourceTree = "<group>"; };
131 CBF4AF1A1EE667CA0029CE7D /* FirmwareWriteController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FirmwareWriteController.xib; sourceTree = "<group>"; };
132 CBF4AF221EE670650029CE7D /* FirmwareDownloadControllerTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FirmwareDownloadControllerTableViewCell.h; sourceTree = "<group>"; };
133 CBF4AF231EE670650029CE7D /* FirmwareDownloadControllerTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirmwareDownloadControllerTableViewCell.m; sourceTree = "<group>"; };
134 CBF4AF241EE670650029CE7D /* FirmwareDownloadControllerTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FirmwareDownloadControllerTableViewCell.xib; sourceTree = "<group>"; };
135 CBF4AF2A1EE6AD660029CE7D /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = ../../../../../../usr/lib/libsqlite3.dylib; sourceTree = "<group>"; };
136 CBF4AF371EE6F1C60029CE7D /* DBManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBManager.h; sourceTree = SOURCE_ROOT; };
137 CBF4AF381EE6F1F80029CE7D /* DBManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBManager.m; sourceTree = SOURCE_ROOT; };
138 CBF4AF3A1EE7C8F00029CE7D /* FirmwareWriteControllerTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FirmwareWriteControllerTableViewCell.h; sourceTree = "<group>"; };
139 CBF4AF3B1EE7C8F00029CE7D /* FirmwareWriteControllerTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirmwareWriteControllerTableViewCell.m; sourceTree = "<group>"; };
140 CBF4AF3C1EE7C8F00029CE7D /* FirmwareWriteControllerTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FirmwareWriteControllerTableViewCell.xib; sourceTree = "<group>"; };
141 CBF4AF3F1EE7EE290029CE7D /* NSData+NSString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+NSString.h"; sourceTree = "<group>"; };
142 CBF4AF401EE7EE290029CE7D /* NSData+NSString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+NSString.m"; sourceTree = "<group>"; };
143 CE3077231F8E259000EB87FF /* jacket_test_ios-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "jacket_test_ios-Bridging-Header.h"; sourceTree = "<group>"; };
144 CE3077261F8E289100EB87FF /* DemoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoView.swift; sourceTree = "<group>"; };
145 CE3077291F8E2BD700EB87FF /* SenserData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SenserData.swift; sourceTree = "<group>"; };
146 CE30772C1F8E36BD00EB87FF /* UserNofitication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNofitication.swift; sourceTree = "<group>"; };
147 CE30772E1F8E36E500EB87FF /* UNResponseManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UNResponseManager.swift; sourceTree = "<group>"; };
148 CE3077301F8E37DA00EB87FF /* Caller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Caller.swift; sourceTree = "<group>"; };
149 /* End PBXFileReference section */
150
151 /* Begin PBXFrameworksBuildPhase section */
152 CBE48CBD1CD07F0A0089DAF2 /* Frameworks */ = {
153 isa = PBXFrameworksBuildPhase;
154 buildActionMask = 2147483647;
155 files = (
156 CBF4AF2B1EE6AD660029CE7D /* libsqlite3.dylib in Frameworks */,
157 CBE48CDB1CD080120089DAF2 /* CoreBluetooth.framework in Frameworks */,
158 );
159 runOnlyForDeploymentPostprocessing = 0;
160 };
161 /* End PBXFrameworksBuildPhase section */
162
163 /* Begin PBXGroup section */
164 446613201E134FD500A56C82 /* Settings */ = {
165 isa = PBXGroup;
166 children = (
167 446613171E134FC000A56C82 /* SettingsController.h */,
168 446613181E134FC000A56C82 /* SettingsController.m */,
169 446613191E134FC000A56C82 /* SettingsController.xib */,
170 CB34DA281E5E9C4B00EBA2E4 /* InputMotorController.h */,
171 CB34DA291E5E9C4B00EBA2E4 /* InputMotorController.m */,
172 CB34DA261E5E9C2200EBA2E4 /* InputMotorController.xib */,
173 CBF4AEF51EE54DE10029CE7D /* FirmwareUpdateController.h */,
174 CBF4AEF61EE54DE10029CE7D /* FirmwareUpdateController.m */,
175 CBF4AEF31EE54D910029CE7D /* FirmwareUpdateController.xib */,
176 CBF4AF131EE667B70029CE7D /* FirmwareDownloadController.h */,
177 CBF4AF141EE667B70029CE7D /* FirmwareDownloadController.m */,
178 CBF4AF151EE667B70029CE7D /* FirmwareDownloadController.xib */,
179 CBF4AF221EE670650029CE7D /* FirmwareDownloadControllerTableViewCell.h */,
180 CBF4AF231EE670650029CE7D /* FirmwareDownloadControllerTableViewCell.m */,
181 CBF4AF241EE670650029CE7D /* FirmwareDownloadControllerTableViewCell.xib */,
182 CBF4AF181EE667CA0029CE7D /* FirmwareWriteController.h */,
183 CBF4AF191EE667CA0029CE7D /* FirmwareWriteController.m */,
184 CBF4AF1A1EE667CA0029CE7D /* FirmwareWriteController.xib */,
185 CBF4AF3A1EE7C8F00029CE7D /* FirmwareWriteControllerTableViewCell.h */,
186 CBF4AF3B1EE7C8F00029CE7D /* FirmwareWriteControllerTableViewCell.m */,
187 CBF4AF3C1EE7C8F00029CE7D /* FirmwareWriteControllerTableViewCell.xib */,
188 CBE0DBC41F25804D00E765A4 /* EepromController.h */,
189 CBE0DBC51F25804D00E765A4 /* EepromController.m */,
190 CBE0DBC61F25804D00E765A4 /* EepromController.xib */,
191 CBE0DBC91F258A4000E765A4 /* EepromTemplateController.h */,
192 CBE0DBCA1F258A4000E765A4 /* EepromTemplateController.m */,
193 CBE0DBCB1F258A4000E765A4 /* EepromTemplateController.xib */,
194 CBE0DBCE1F258A7400E765A4 /* EepromTemplateTableViewCell.h */,
195 CBE0DBCF1F258A7400E765A4 /* EepromTemplateTableViewCell.m */,
196 CBE0DBD01F258A7400E765A4 /* EepromTemplateTableViewCell.xib */,
197 CBE0DBD31F25DDE600E765A4 /* BootSettingController.h */,
198 CBE0DBD41F25DDE600E765A4 /* BootSettingController.m */,
199 CBE0DBD51F25DDE600E765A4 /* BootSettingController.xib */,
200 CB53F4541F871AF300970458 /* InputSoundController.h */,
201 CB53F4551F871AF300970458 /* InputSoundController.m */,
202 CB53F4561F871AF300970458 /* InputSoundController.xib */,
203 CE3077261F8E289100EB87FF /* DemoView.swift */,
204 );
205 name = Settings;
206 path = ..;
207 sourceTree = "<group>";
208 };
209 CBE48CB71CD07F0A0089DAF2 = {
210 isa = PBXGroup;
211 children = (
212 CBE48CC21CD07F0A0089DAF2 /* jacket_test_ios */,
213 CBF4AF111EE638870029CE7D /* Other Sources */,
214 CBE48CDD1CD084740089DAF2 /* BLE */,
215 CBF4AEF81EE55AF20029CE7D /* 3rdParties */,
216 CBE48CDC1CD080280089DAF2 /* Frameworks */,
217 CBE48CC11CD07F0A0089DAF2 /* Products */,
218 );
219 sourceTree = "<group>";
220 };
221 CBE48CC11CD07F0A0089DAF2 /* Products */ = {
222 isa = PBXGroup;
223 children = (
224 CBE48CC01CD07F0A0089DAF2 /* jacket_test_ios.app */,
225 );
226 name = Products;
227 sourceTree = "<group>";
228 };
229 CBE48CC21CD07F0A0089DAF2 /* jacket_test_ios */ = {
230 isa = PBXGroup;
231 children = (
232 CE30772B1F8E369C00EB87FF /* util */,
233 CE3077281F8E2BBE00EB87FF /* model */,
234 CBF4AF0D1EE637430029CE7D /* Operation */,
235 446613201E134FD500A56C82 /* Settings */,
236 CBE48CC61CD07F0A0089DAF2 /* AppDelegate.h */,
237 CBE48CC71CD07F0A0089DAF2 /* AppDelegate.m */,
238 CBF4AF371EE6F1C60029CE7D /* DBManager.h */,
239 CBF4AF381EE6F1F80029CE7D /* DBManager.m */,
240 CBE48CC91CD07F0A0089DAF2 /* BleSearchViewController.h */,
241 CBE48CCA1CD07F0A0089DAF2 /* BleSearchViewController.m */,
242 CBE644091F30614800664E68 /* BleSearchResultTableViewController.h */,
243 CBE6440A1F30614800664E68 /* BleSearchResultTableViewController.m */,
244 CBE644071F30614800664E68 /* BleSearchResultTableViewCell.h */,
245 CBE644081F30614800664E68 /* BleSearchResultTableViewCell.m */,
246 CBE48CCC1CD07F0A0089DAF2 /* Main.storyboard */,
247 CBE48CCF1CD07F0A0089DAF2 /* Assets.xcassets */,
248 CBE48CD11CD07F0A0089DAF2 /* LaunchScreen.storyboard */,
249 CBE48CD41CD07F0A0089DAF2 /* Info.plist */,
250 CBE48CEE1CD0B2700089DAF2 /* Protocol */,
251 CBE48CC31CD07F0A0089DAF2 /* Supporting Files */,
252 CBE48CFE1CD0B6AA0089DAF2 /* BleControl.h */,
253 CBE48CFF1CD0B6AA0089DAF2 /* BleControl.m */,
254 CBF4AF3F1EE7EE290029CE7D /* NSData+NSString.h */,
255 CBF4AF401EE7EE290029CE7D /* NSData+NSString.m */,
256 CE3077231F8E259000EB87FF /* jacket_test_ios-Bridging-Header.h */,
257 );
258 path = jacket_test_ios;
259 sourceTree = "<group>";
260 };
261 CBE48CC31CD07F0A0089DAF2 /* Supporting Files */ = {
262 isa = PBXGroup;
263 children = (
264 CBE48CC41CD07F0A0089DAF2 /* main.m */,
265 );
266 name = "Supporting Files";
267 sourceTree = "<group>";
268 };
269 CBE48CDC1CD080280089DAF2 /* Frameworks */ = {
270 isa = PBXGroup;
271 children = (
272 CBF4AF2A1EE6AD660029CE7D /* libsqlite3.dylib */,
273 CBE48CDA1CD080120089DAF2 /* CoreBluetooth.framework */,
274 );
275 name = Frameworks;
276 sourceTree = "<group>";
277 };
278 CBE48CDD1CD084740089DAF2 /* BLE */ = {
279 isa = PBXGroup;
280 children = (
281 CBE48CDE1CD084740089DAF2 /* BLE.h */,
282 CBE48CDF1CD084740089DAF2 /* BLE.m */,
283 CBE48CE01CD084740089DAF2 /* BLEDefines.h */,
284 );
285 path = BLE;
286 sourceTree = "<group>";
287 };
288 CBE48CEE1CD0B2700089DAF2 /* Protocol */ = {
289 isa = PBXGroup;
290 children = (
291 CBE48CF91CD0B3D50089DAF2 /* BleProtocol.h */,
292 CBE48CF71CD0B3C30089DAF2 /* BleProtocol.m */,
293 );
294 name = Protocol;
295 sourceTree = "<group>";
296 };
297 CBF4AEF81EE55AF20029CE7D /* 3rdParties */ = {
298 isa = PBXGroup;
299 children = (
300 CBF4AEF91EE55B620029CE7D /* AFNetworking */,
301 );
302 name = 3rdParties;
303 sourceTree = "<group>";
304 };
305 CBF4AEF91EE55B620029CE7D /* AFNetworking */ = {
306 isa = PBXGroup;
307 children = (
308 CBF4AEFA1EE55B620029CE7D /* AFHTTPSessionManager.h */,
309 CBF4AEFB1EE55B620029CE7D /* AFHTTPSessionManager.m */,
310 CBF4AEFC1EE55B620029CE7D /* AFNetworking.h */,
311 CBF4AEFD1EE55B620029CE7D /* AFNetworkReachabilityManager.h */,
312 CBF4AEFE1EE55B620029CE7D /* AFNetworkReachabilityManager.m */,
313 CBF4AEFF1EE55B620029CE7D /* AFSecurityPolicy.h */,
314 CBF4AF001EE55B620029CE7D /* AFSecurityPolicy.m */,
315 CBF4AF011EE55B620029CE7D /* AFURLRequestSerialization.h */,
316 CBF4AF021EE55B620029CE7D /* AFURLRequestSerialization.m */,
317 CBF4AF031EE55B620029CE7D /* AFURLResponseSerialization.h */,
318 CBF4AF041EE55B620029CE7D /* AFURLResponseSerialization.m */,
319 CBF4AF051EE55B620029CE7D /* AFURLSessionManager.h */,
320 CBF4AF061EE55B620029CE7D /* AFURLSessionManager.m */,
321 );
322 name = AFNetworking;
323 path = 3rdParties/AFNetworking;
324 sourceTree = "<group>";
325 };
326 CBF4AF0D1EE637430029CE7D /* Operation */ = {
327 isa = PBXGroup;
328 children = (
329 CBF4AF0E1EE637830029CE7D /* Operation.h */,
330 CBF4AF0F1EE637830029CE7D /* Operation.m */,
331 );
332 name = Operation;
333 sourceTree = "<group>";
334 };
335 CBF4AF111EE638870029CE7D /* Other Sources */ = {
336 isa = PBXGroup;
337 children = (
338 CBF4AF121EE6389C0029CE7D /* jacket_test_ios_prefix.pch */,
339 );
340 name = "Other Sources";
341 path = jacket_ios;
342 sourceTree = "<group>";
343 };
344 CE3077281F8E2BBE00EB87FF /* model */ = {
345 isa = PBXGroup;
346 children = (
347 CE3077291F8E2BD700EB87FF /* SenserData.swift */,
348 );
349 name = model;
350 sourceTree = "<group>";
351 };
352 CE30772B1F8E369C00EB87FF /* util */ = {
353 isa = PBXGroup;
354 children = (
355 CE30772C1F8E36BD00EB87FF /* UserNofitication.swift */,
356 CE30772E1F8E36E500EB87FF /* UNResponseManager.swift */,
357 CE3077301F8E37DA00EB87FF /* Caller.swift */,
358 );
359 name = util;
360 sourceTree = "<group>";
361 };
362 /* End PBXGroup section */
363
364 /* Begin PBXNativeTarget section */
365 CBE48CBF1CD07F0A0089DAF2 /* jacket_test_ios */ = {
366 isa = PBXNativeTarget;
367 buildConfigurationList = CBE48CD71CD07F0A0089DAF2 /* Build configuration list for PBXNativeTarget "jacket_test_ios" */;
368 buildPhases = (
369 CBE48CBC1CD07F0A0089DAF2 /* Sources */,
370 CBE48CBD1CD07F0A0089DAF2 /* Frameworks */,
371 CBE48CBE1CD07F0A0089DAF2 /* Resources */,
372 );
373 buildRules = (
374 );
375 dependencies = (
376 );
377 name = jacket_test_ios;
378 productName = jacket_ios;
379 productReference = CBE48CC01CD07F0A0089DAF2 /* jacket_test_ios.app */;
380 productType = "com.apple.product-type.application";
381 };
382 /* End PBXNativeTarget section */
383
384 /* Begin PBXProject section */
385 CBE48CB81CD07F0A0089DAF2 /* Project object */ = {
386 isa = PBXProject;
387 attributes = {
388 LastUpgradeCheck = 0900;
389 ORGANIZATIONNAME = "ドラッサル 亜嵐";
390 TargetAttributes = {
391 CBE48CBF1CD07F0A0089DAF2 = {
392 CreatedOnToolsVersion = 7.2;
393 DevelopmentTeam = 7KP2X5K7RJ;
394 LastSwiftMigration = 0900;
395 ProvisioningStyle = Automatic;
396 };
397 };
398 };
399 buildConfigurationList = CBE48CBB1CD07F0A0089DAF2 /* Build configuration list for PBXProject "jacket_test_ios" */;
400 compatibilityVersion = "Xcode 3.2";
401 developmentRegion = English;
402 hasScannedForEncodings = 0;
403 knownRegions = (
404 en,
405 Base,
406 );
407 mainGroup = CBE48CB71CD07F0A0089DAF2;
408 productRefGroup = CBE48CC11CD07F0A0089DAF2 /* Products */;
409 projectDirPath = "";
410 projectRoot = "";
411 targets = (
412 CBE48CBF1CD07F0A0089DAF2 /* jacket_test_ios */,
413 );
414 };
415 /* End PBXProject section */
416
417 /* Begin PBXResourcesBuildPhase section */
418 CBE48CBE1CD07F0A0089DAF2 /* Resources */ = {
419 isa = PBXResourcesBuildPhase;
420 buildActionMask = 2147483647;
421 files = (
422 CBE48CD31CD07F0A0089DAF2 /* LaunchScreen.storyboard in Resources */,
423 CBF4AEF41EE54D910029CE7D /* FirmwareUpdateController.xib in Resources */,
424 CBE48CD01CD07F0A0089DAF2 /* Assets.xcassets in Resources */,
425 CBE0DBCD1F258A4000E765A4 /* EepromTemplateController.xib in Resources */,
426 CBF4AF1C1EE667CA0029CE7D /* FirmwareWriteController.xib in Resources */,
427 CBF4AF3E1EE7C8F00029CE7D /* FirmwareWriteControllerTableViewCell.xib in Resources */,
428 CBE0DBD21F258A7400E765A4 /* EepromTemplateTableViewCell.xib in Resources */,
429 CBF4AF171EE667B70029CE7D /* FirmwareDownloadController.xib in Resources */,
430 CBF4AF261EE670650029CE7D /* FirmwareDownloadControllerTableViewCell.xib in Resources */,
431 CBE0DBD71F25DDE600E765A4 /* BootSettingController.xib in Resources */,
432 CBE0DBC81F25804D00E765A4 /* EepromController.xib in Resources */,
433 CB53F4581F871AF300970458 /* InputSoundController.xib in Resources */,
434 4466131F1E134FC000A56C82 /* SettingsController.xib in Resources */,
435 CB34DA271E5E9C2200EBA2E4 /* InputMotorController.xib in Resources */,
436 CBE48CCE1CD07F0A0089DAF2 /* Main.storyboard in Resources */,
437 );
438 runOnlyForDeploymentPostprocessing = 0;
439 };
440 /* End PBXResourcesBuildPhase section */
441
442 /* Begin PBXSourcesBuildPhase section */
443 CBE48CBC1CD07F0A0089DAF2 /* Sources */ = {
444 isa = PBXSourcesBuildPhase;
445 buildActionMask = 2147483647;
446 files = (
447 CBE0DBD61F25DDE600E765A4 /* BootSettingController.m in Sources */,
448 CBF4AF091EE55B620029CE7D /* AFSecurityPolicy.m in Sources */,
449 CBE6440B1F30614800664E68 /* BleSearchResultTableViewCell.m in Sources */,
450 CBE48CCB1CD07F0A0089DAF2 /* BleSearchViewController.m in Sources */,
451 CE30772F1F8E36E500EB87FF /* UNResponseManager.swift in Sources */,
452 CBF4AF411EE7EE290029CE7D /* NSData+NSString.m in Sources */,
453 4466131E1E134FC000A56C82 /* SettingsController.m in Sources */,
454 CBF4AF391EE6F1F80029CE7D /* DBManager.m in Sources */,
455 CBF4AF161EE667B70029CE7D /* FirmwareDownloadController.m in Sources */,
456 CBE48CC81CD07F0A0089DAF2 /* AppDelegate.m in Sources */,
457 CBE0DBCC1F258A4000E765A4 /* EepromTemplateController.m in Sources */,
458 CB34DA2A1E5E9C4B00EBA2E4 /* InputMotorController.m in Sources */,
459 CBE0DBC71F25804D00E765A4 /* EepromController.m in Sources */,
460 CBE48CC51CD07F0A0089DAF2 /* main.m in Sources */,
461 CE30772A1F8E2BD700EB87FF /* SenserData.swift in Sources */,
462 CE3077271F8E289100EB87FF /* DemoView.swift in Sources */,
463 CBF4AF0C1EE55B620029CE7D /* AFURLSessionManager.m in Sources */,
464 CBF4AF101EE637830029CE7D /* Operation.m in Sources */,
465 CE3077311F8E37DA00EB87FF /* Caller.swift in Sources */,
466 CBE6440C1F30614800664E68 /* BleSearchResultTableViewController.m in Sources */,
467 CBF4AF1B1EE667CA0029CE7D /* FirmwareWriteController.m in Sources */,
468 CBF4AF3D1EE7C8F00029CE7D /* FirmwareWriteControllerTableViewCell.m in Sources */,
469 CBE48D001CD0B6AA0089DAF2 /* BleControl.m in Sources */,
470 CBE48CE11CD084740089DAF2 /* BLE.m in Sources */,
471 CB53F4571F871AF300970458 /* InputSoundController.m in Sources */,
472 CBF4AF071EE55B620029CE7D /* AFHTTPSessionManager.m in Sources */,
473 CBF4AF0B1EE55B620029CE7D /* AFURLResponseSerialization.m in Sources */,
474 CE30772D1F8E36BD00EB87FF /* UserNofitication.swift in Sources */,
475 CBE48CF81CD0B3C30089DAF2 /* BleProtocol.m in Sources */,
476 CBF4AF251EE670650029CE7D /* FirmwareDownloadControllerTableViewCell.m in Sources */,
477 CBF4AF0A1EE55B620029CE7D /* AFURLRequestSerialization.m in Sources */,
478 CBF4AEF71EE54DE10029CE7D /* FirmwareUpdateController.m in Sources */,
479 CBE0DBD11F258A7400E765A4 /* EepromTemplateTableViewCell.m in Sources */,
480 CBF4AF081EE55B620029CE7D /* AFNetworkReachabilityManager.m in Sources */,
481 );
482 runOnlyForDeploymentPostprocessing = 0;
483 };
484 /* End PBXSourcesBuildPhase section */
485
486 /* Begin PBXVariantGroup section */
487 CBE48CCC1CD07F0A0089DAF2 /* Main.storyboard */ = {
488 isa = PBXVariantGroup;
489 children = (
490 CBE48CCD1CD07F0A0089DAF2 /* Base */,
491 );
492 name = Main.storyboard;
493 sourceTree = "<group>";
494 };
495 CBE48CD11CD07F0A0089DAF2 /* LaunchScreen.storyboard */ = {
496 isa = PBXVariantGroup;
497 children = (
498 CBE48CD21CD07F0A0089DAF2 /* Base */,
499 );
500 name = LaunchScreen.storyboard;
501 sourceTree = "<group>";
502 };
503 /* End PBXVariantGroup section */
504
505 /* Begin XCBuildConfiguration section */
506 CBE48CD51CD07F0A0089DAF2 /* Debug */ = {
507 isa = XCBuildConfiguration;
508 buildSettings = {
509 ALWAYS_SEARCH_USER_PATHS = NO;
510 CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
511 CLANG_CXX_LIBRARY = "libc++";
512 CLANG_ENABLE_MODULES = YES;
513 CLANG_ENABLE_OBJC_ARC = YES;
514 CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
515 CLANG_WARN_BOOL_CONVERSION = YES;
516 CLANG_WARN_COMMA = YES;
517 CLANG_WARN_CONSTANT_CONVERSION = YES;
518 CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
519 CLANG_WARN_EMPTY_BODY = YES;
520 CLANG_WARN_ENUM_CONVERSION = YES;
521 CLANG_WARN_INFINITE_RECURSION = YES;
522 CLANG_WARN_INT_CONVERSION = YES;
523 CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
524 CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
525 CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
526 CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
527 CLANG_WARN_STRICT_PROTOTYPES = YES;
528 CLANG_WARN_SUSPICIOUS_MOVE = YES;
529 CLANG_WARN_UNREACHABLE_CODE = YES;
530 CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
531 "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
532 COPY_PHASE_STRIP = NO;
533 DEBUG_INFORMATION_FORMAT = dwarf;
534 ENABLE_STRICT_OBJC_MSGSEND = YES;
535 ENABLE_TESTABILITY = YES;
536 GCC_C_LANGUAGE_STANDARD = gnu99;
537 GCC_DYNAMIC_NO_PIC = NO;
538 GCC_NO_COMMON_BLOCKS = YES;
539 GCC_OPTIMIZATION_LEVEL = 0;
540 GCC_PREFIX_HEADER = jacket_test_ios_prefix.pch;
541 GCC_PREPROCESSOR_DEFINITIONS = (
542 "DEBUG=1",
543 "$(inherited)",
544 );
545 GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
546 GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
547 GCC_WARN_UNDECLARED_SELECTOR = YES;
548 GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
549 GCC_WARN_UNUSED_FUNCTION = YES;
550 GCC_WARN_UNUSED_VARIABLE = YES;
551 IPHONEOS_DEPLOYMENT_TARGET = 10.3;
552 MTL_ENABLE_DEBUG_INFO = YES;
553 ONLY_ACTIVE_ARCH = YES;
554 SDKROOT = iphoneos;
555 TARGETED_DEVICE_FAMILY = "1,2";
556 USER_HEADER_SEARCH_PATHS = 3rdParties;
557 };
558 name = Debug;
559 };
560 CBE48CD61CD07F0A0089DAF2 /* Release */ = {
561 isa = XCBuildConfiguration;
562 buildSettings = {
563 ALWAYS_SEARCH_USER_PATHS = NO;
564 CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
565 CLANG_CXX_LIBRARY = "libc++";
566 CLANG_ENABLE_MODULES = YES;
567 CLANG_ENABLE_OBJC_ARC = YES;
568 CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
569 CLANG_WARN_BOOL_CONVERSION = YES;
570 CLANG_WARN_COMMA = YES;
571 CLANG_WARN_CONSTANT_CONVERSION = YES;
572 CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
573 CLANG_WARN_EMPTY_BODY = YES;
574 CLANG_WARN_ENUM_CONVERSION = YES;
575 CLANG_WARN_INFINITE_RECURSION = YES;
576 CLANG_WARN_INT_CONVERSION = YES;
577 CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
578 CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
579 CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
580 CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
581 CLANG_WARN_STRICT_PROTOTYPES = YES;
582 CLANG_WARN_SUSPICIOUS_MOVE = YES;
583 CLANG_WARN_UNREACHABLE_CODE = YES;
584 CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
585 "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
586 COPY_PHASE_STRIP = NO;
587 DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
588 ENABLE_NS_ASSERTIONS = NO;
589 ENABLE_STRICT_OBJC_MSGSEND = YES;
590 GCC_C_LANGUAGE_STANDARD = gnu99;
591 GCC_NO_COMMON_BLOCKS = YES;
592 GCC_PREFIX_HEADER = jacket_test_ios_prefix.pch;
593 GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
594 GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
595 GCC_WARN_UNDECLARED_SELECTOR = YES;
596 GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
597 GCC_WARN_UNUSED_FUNCTION = YES;
598 GCC_WARN_UNUSED_VARIABLE = YES;
599 IPHONEOS_DEPLOYMENT_TARGET = 10.3;
600 MTL_ENABLE_DEBUG_INFO = NO;
601 SDKROOT = iphoneos;
602 SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
603 TARGETED_DEVICE_FAMILY = "1,2";
604 USER_HEADER_SEARCH_PATHS = 3rdParties;
605 VALIDATE_PRODUCT = YES;
606 };
607 name = Release;
608 };
609 CBE48CD81CD07F0A0089DAF2 /* Debug */ = {
610 isa = XCBuildConfiguration;
611 buildSettings = {
612 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
613 CLANG_ENABLE_MODULES = YES;
614 CODE_SIGN_IDENTITY = "iPhone Developer";
615 "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
616 CODE_SIGN_STYLE = Automatic;
617 DEVELOPMENT_TEAM = 7KP2X5K7RJ;
618 INFOPLIST_FILE = jacket_test_ios/Info.plist;
619 IPHONEOS_DEPLOYMENT_TARGET = 8.0;
620 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
621 PRODUCT_BUNDLE_IDENTIFIER = "com.momo-ltd.jackettestios";
622 PRODUCT_NAME = "$(TARGET_NAME)";
623 PROVISIONING_PROFILE = "";
624 PROVISIONING_PROFILE_SPECIFIER = "";
625 SWIFT_OBJC_BRIDGING_HEADER = "jacket_test_ios/jacket_test_ios-Bridging-Header.h";
626 SWIFT_OPTIMIZATION_LEVEL = "-Onone";
627 SWIFT_VERSION = 3.0;
628 };
629 name = Debug;
630 };
631 CBE48CD91CD07F0A0089DAF2 /* Release */ = {
632 isa = XCBuildConfiguration;
633 buildSettings = {
634 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
635 CLANG_ENABLE_MODULES = YES;
636 CODE_SIGN_IDENTITY = "iPhone Developer";
637 "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
638 CODE_SIGN_STYLE = Automatic;
639 DEVELOPMENT_TEAM = 7KP2X5K7RJ;
640 INFOPLIST_FILE = jacket_test_ios/Info.plist;
641 IPHONEOS_DEPLOYMENT_TARGET = 8.0;
642 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
643 PRODUCT_BUNDLE_IDENTIFIER = "com.momo-ltd.jackettestios";
644 PRODUCT_NAME = "$(TARGET_NAME)";
645 PROVISIONING_PROFILE = "";
646 PROVISIONING_PROFILE_SPECIFIER = "";
647 SWIFT_OBJC_BRIDGING_HEADER = "jacket_test_ios/jacket_test_ios-Bridging-Header.h";
648 SWIFT_VERSION = 3.0;
649 };
650 name = Release;
651 };
652 /* End XCBuildConfiguration section */
653
654 /* Begin XCConfigurationList section */
655 CBE48CBB1CD07F0A0089DAF2 /* Build configuration list for PBXProject "jacket_test_ios" */ = {
656 isa = XCConfigurationList;
657 buildConfigurations = (
658 CBE48CD51CD07F0A0089DAF2 /* Debug */,
659 CBE48CD61CD07F0A0089DAF2 /* Release */,
660 );
661 defaultConfigurationIsVisible = 0;
662 defaultConfigurationName = Release;
663 };
664 CBE48CD71CD07F0A0089DAF2 /* Build configuration list for PBXNativeTarget "jacket_test_ios" */ = {
665 isa = XCConfigurationList;
666 buildConfigurations = (
667 CBE48CD81CD07F0A0089DAF2 /* Debug */,
668 CBE48CD91CD07F0A0089DAF2 /* Release */,
669 );
670 defaultConfigurationIsVisible = 0;
671 defaultConfigurationName = Release;
672 };
673 /* End XCConfigurationList section */
674 };
675 rootObject = CBE48CB81CD07F0A0089DAF2 /* Project object */;
676 }
1 //
2 // AppDelegate.h
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2016/04/27.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10
11 @interface AppDelegate : UIResponder <UIApplicationDelegate>
12
13 @property (strong, nonatomic) UIWindow *window;
14
15
16 @end
17
1 //
2 // AppDelegate.m
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2016/04/27.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "AppDelegate.h"
10 #import "jacket_test_ios-Swift.h"
11 @interface AppDelegate ()
12
13 @end
14
15 @implementation AppDelegate
16
17
18 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 // Override point for customization after application launch.
20 return [[Caller sheardInstance]application:application didFinishLaunchingWithOptions:launchOptions];
21 }
22
23 - (void)applicationWillResignActive:(UIApplication *)application {
24 // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
25 // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
26 }
27
28 - (void)applicationDidEnterBackground:(UIApplication *)application {
29 // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
30 // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 }
32
33 - (void)applicationWillEnterForeground:(UIApplication *)application {
34 // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
35 }
36
37 - (void)applicationDidBecomeActive:(UIApplication *)application {
38 // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
39 }
40
41 - (void)applicationWillTerminate:(UIApplication *)application {
42 // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 }
44
45 @end
1 {
2 "images" : [
3 {
4 "idiom" : "iphone",
5 "size" : "20x20",
6 "scale" : "2x"
7 },
8 {
9 "idiom" : "iphone",
10 "size" : "20x20",
11 "scale" : "3x"
12 },
13 {
14 "idiom" : "iphone",
15 "size" : "29x29",
16 "scale" : "2x"
17 },
18 {
19 "idiom" : "iphone",
20 "size" : "29x29",
21 "scale" : "3x"
22 },
23 {
24 "idiom" : "iphone",
25 "size" : "40x40",
26 "scale" : "2x"
27 },
28 {
29 "idiom" : "iphone",
30 "size" : "40x40",
31 "scale" : "3x"
32 },
33 {
34 "idiom" : "iphone",
35 "size" : "60x60",
36 "scale" : "2x"
37 },
38 {
39 "idiom" : "iphone",
40 "size" : "60x60",
41 "scale" : "3x"
42 },
43 {
44 "idiom" : "ipad",
45 "size" : "20x20",
46 "scale" : "1x"
47 },
48 {
49 "idiom" : "ipad",
50 "size" : "20x20",
51 "scale" : "2x"
52 },
53 {
54 "idiom" : "ipad",
55 "size" : "29x29",
56 "scale" : "1x"
57 },
58 {
59 "idiom" : "ipad",
60 "size" : "29x29",
61 "scale" : "2x"
62 },
63 {
64 "idiom" : "ipad",
65 "size" : "40x40",
66 "scale" : "1x"
67 },
68 {
69 "idiom" : "ipad",
70 "size" : "40x40",
71 "scale" : "2x"
72 },
73 {
74 "idiom" : "ipad",
75 "size" : "76x76",
76 "scale" : "1x"
77 },
78 {
79 "idiom" : "ipad",
80 "size" : "76x76",
81 "scale" : "2x"
82 },
83 {
84 "idiom" : "ipad",
85 "size" : "83.5x83.5",
86 "scale" : "2x"
87 }
88 ],
89 "info" : {
90 "version" : 1,
91 "author" : "xcode"
92 }
93 }
...\ No newline at end of file ...\ No newline at end of file
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
3 <device id="retina4_7" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
8 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9 </dependencies>
10 <scenes>
11 <!--View Controller-->
12 <scene sceneID="EHf-IW-A2E">
13 <objects>
14 <viewController id="01J-lp-oVM" sceneMemberID="viewController">
15 <layoutGuides>
16 <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
17 <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
18 </layoutGuides>
19 <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
20 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
21 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
22 <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
23 </view>
24 </viewController>
25 <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
26 </objects>
27 <point key="canvasLocation" x="53" y="375"/>
28 </scene>
29 </scenes>
30 </document>
1 <?xml version="1.0" encoding="UTF-8"?>
2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Jcl-sF-EGT">
3 <device id="retina4_7" orientation="portrait">
4 <adaptation id="fullscreen"/>
5 </device>
6 <dependencies>
7 <deployment identifier="iOS"/>
8 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13173"/>
9 <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
10 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
11 </dependencies>
12 <scenes>
13 <!--BLEの検索-->
14 <scene sceneID="tne-QT-ifu">
15 <objects>
16 <viewController id="BYZ-38-t0r" userLabel="BLEの検索" customClass="BleSearchViewController" sceneMemberID="viewController">
17 <layoutGuides>
18 <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
19 <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
20 </layoutGuides>
21 <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
22 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
23 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
24 <subviews>
25 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zgC-Yy-hfH">
26 <rect key="frame" x="146" y="318.5" width="83" height="30"/>
27 <constraints>
28 <constraint firstAttribute="width" constant="83" id="Qng-i0-OaI"/>
29 </constraints>
30 <state key="normal" title="Scan"/>
31 <connections>
32 <action selector="btnConnectClicked:" destination="BYZ-38-t0r" eventType="touchUpInside" id="Qar-ro-0Px"/>
33 </connections>
34 </button>
35 <activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="tJd-HG-X4C">
36 <rect key="frame" x="177.5" y="274.5" width="20" height="20"/>
37 </activityIndicatorView>
38 </subviews>
39 <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
40 <constraints>
41 <constraint firstItem="zgC-Yy-hfH" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="3Jq-Zt-IcV"/>
42 <constraint firstItem="tJd-HG-X4C" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="mt3-aS-n2r"/>
43 <constraint firstItem="zgC-Yy-hfH" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="wCI-lZ-WuA"/>
44 <constraint firstItem="zgC-Yy-hfH" firstAttribute="top" secondItem="tJd-HG-X4C" secondAttribute="bottom" constant="24" id="wkQ-pr-QRo"/>
45 </constraints>
46 </view>
47 <navigationItem key="navigationItem" title="BLEの検索" id="SM2-MW-czc"/>
48 <connections>
49 <outlet property="activityScanning" destination="tJd-HG-X4C" id="yK2-cc-98U"/>
50 <segue destination="fry-cf-FRa" kind="show" identifier="idSegueBleDeviceList" id="lA6-Ow-MYV"/>
51 </connections>
52 </viewController>
53 <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
54 </objects>
55 <point key="canvasLocation" x="905" y="429"/>
56 </scene>
57 <!--BLE検索の結果-->
58 <scene sceneID="KmE-QO-shw">
59 <objects>
60 <tableViewController id="fry-cf-FRa" customClass="BleSearchResultTableViewController" sceneMemberID="viewController">
61 <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="58" sectionHeaderHeight="28" sectionFooterHeight="28" id="Fuw-mT-WaZ">
62 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
63 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
64 <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
65 <prototypes>
66 <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="cell_uuid" rowHeight="58" id="u9M-5X-FJa" customClass="BleSearchResultTableViewCell">
67 <rect key="frame" x="0.0" y="28" width="375" height="58"/>
68 <autoresizingMask key="autoresizingMask"/>
69 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="u9M-5X-FJa" id="QlV-zH-myQ">
70 <rect key="frame" x="0.0" y="0.0" width="375" height="57.5"/>
71 <autoresizingMask key="autoresizingMask"/>
72 <subviews>
73 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="NAME" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cy4-HT-u0h" userLabel="lblName">
74 <rect key="frame" x="15" y="31" width="47.5" height="21"/>
75 <fontDescription key="fontDescription" type="system" pointSize="17"/>
76 <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
77 <nil key="highlightedColor"/>
78 </label>
79 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="RSSI" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uxz-0k-13E" userLabel="lblRssi">
80 <rect key="frame" x="331" y="31" width="36" height="21"/>
81 <fontDescription key="fontDescription" type="system" pointSize="17"/>
82 <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
83 <nil key="highlightedColor"/>
84 </label>
85 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="UUID" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yFY-1X-zf0" userLabel="lblUuid">
86 <rect key="frame" x="15" y="8" width="41" height="21"/>
87 <fontDescription key="fontDescription" type="system" pointSize="17"/>
88 <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
89 <nil key="highlightedColor"/>
90 </label>
91 </subviews>
92 <constraints>
93 <constraint firstItem="uxz-0k-13E" firstAttribute="trailing" secondItem="QlV-zH-myQ" secondAttribute="trailingMargin" id="9jN-I7-d6c"/>
94 <constraint firstItem="yFY-1X-zf0" firstAttribute="leading" secondItem="QlV-zH-myQ" secondAttribute="leadingMargin" constant="7" id="Rfv-3G-4z8"/>
95 <constraint firstItem="cy4-HT-u0h" firstAttribute="top" secondItem="yFY-1X-zf0" secondAttribute="bottom" constant="2" id="VH3-9l-3uB"/>
96 <constraint firstItem="yFY-1X-zf0" firstAttribute="top" secondItem="QlV-zH-myQ" secondAttribute="topMargin" id="WRh-y7-Cqq"/>
97 <constraint firstItem="cy4-HT-u0h" firstAttribute="leading" secondItem="QlV-zH-myQ" secondAttribute="leadingMargin" constant="7" id="bBQ-ig-FHF"/>
98 <constraint firstItem="uxz-0k-13E" firstAttribute="top" secondItem="QlV-zH-myQ" secondAttribute="topMargin" constant="23" id="j78-Oo-gNJ"/>
99 </constraints>
100 </tableViewCellContentView>
101 <connections>
102 <outlet property="lblName" destination="cy4-HT-u0h" id="41U-YR-Li5"/>
103 <outlet property="lblRssi" destination="uxz-0k-13E" id="bfk-7L-SSb"/>
104 <outlet property="lblUuid" destination="yFY-1X-zf0" id="ziK-NG-Pat"/>
105 </connections>
106 </tableViewCell>
107 </prototypes>
108 <connections>
109 <outlet property="dataSource" destination="fry-cf-FRa" id="dJJ-jv-0L6"/>
110 <outlet property="delegate" destination="fry-cf-FRa" id="tlY-sa-np3"/>
111 </connections>
112 </tableView>
113 <navigationItem key="navigationItem" title="BLE検索の結果" id="1pT-1a-7lI"/>
114 </tableViewController>
115 <placeholder placeholderIdentifier="IBFirstResponder" id="3rJ-4N-e5U" userLabel="First Responder" sceneMemberID="firstResponder"/>
116 </objects>
117 <point key="canvasLocation" x="1781" y="429"/>
118 </scene>
119 <!--Navigation Controller-->
120 <scene sceneID="GkI-08-L2I">
121 <objects>
122 <navigationController automaticallyAdjustsScrollViewInsets="NO" id="Jcl-sF-EGT" sceneMemberID="viewController">
123 <toolbarItems/>
124 <navigationBar key="navigationBar" contentMode="scaleToFill" id="D8Z-ZJ-H0D">
125 <rect key="frame" x="0.0" y="20" width="375" height="44"/>
126 <autoresizingMask key="autoresizingMask"/>
127 </navigationBar>
128 <nil name="viewControllers"/>
129 <connections>
130 <segue destination="BYZ-38-t0r" kind="relationship" relationship="rootViewController" id="W7D-eH-hFH"/>
131 </connections>
132 </navigationController>
133 <placeholder placeholderIdentifier="IBFirstResponder" id="xz5-Ay-Tlj" userLabel="First Responder" sceneMemberID="firstResponder"/>
134 </objects>
135 <point key="canvasLocation" x="93" y="429"/>
136 </scene>
137 </scenes>
138 </document>
1 //
2 // BleControl.h
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2016/04/27.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10 #import "BleProtocol.h"
11 #import "BLE.h"
12
13 @interface BleControl : UIViewController <BLEProtocolDelegate> {
14 IBOutlet UILabel *currentTime;
15 IBOutlet UILabel *currentState;
16 IBOutlet UILabel *currentUsetime;
17 IBOutlet UILabel *currentWalking;
18 IBOutlet UILabel *currentSleep;
19 IBOutlet UILabel *currentWake;
20 bool stateCurrentWalking;
21 }
22
23 @property (strong, nonatomic) BLE *ble;
24 @property (strong, nonatomic) BleProtocol *protocol;
25
26 - (IBAction)btnEditState:(id)sender;
27 - (IBAction)btnEditTime:(id)sender;
28 - (IBAction)btnEditSleep:(id)sender;
29 - (IBAction)btnEditWake:(id)sender;
30 - (IBAction)btnEditWalking:(id)sender;
31 - (IBAction)btnResetUsetime:(id)sender;
32 - (IBAction)btnUsetime:(id)sender;
33 - (void)getNextSlot;
34
35 @end
1 //
2 // BleControl.m
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2016/04/27.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "BleControl.h"
10
11 @interface BleControl ()
12
13 @property (nonatomic) NSInteger slotCounter;
14 @property (nonatomic) NSInteger slotCounterMin;
15 @property (nonatomic) NSInteger slotCounterMax;
16 @property (nonatomic) NSTimer * tmr;
17
18 @end
19
20 @implementation BleControl
21 @synthesize ble;
22 @synthesize protocol;
23
24 - (void)viewDidLoad {
25 [super viewDidLoad];
26
27 // Uncomment the following line to preserve selection between presentations.
28 // self.clearsSelectionOnViewWillAppear = NO;
29
30 // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
31 // self.navigationItem.rightBarButtonItem = self.editButtonItem;
32
33 self.slotCounterMin = 0;
34 self.slotCounterMax = 5;
35 self.slotCounter = self.slotCounterMin;
36 }
37
38 - (void)viewWillAppear:(BOOL)animated {
39 protocol.delegate = self;
40
41 self.tmr = [NSTimer timerWithTimeInterval:0.1
42 target:self
43 selector:@selector(tmrMethod:)
44 userInfo:nil
45 repeats:YES];
46 [[NSRunLoop currentRunLoop] addTimer:self.tmr forMode:NSRunLoopCommonModes];
47 }
48
49 - (void)viewWillDisappear:(BOOL)animated {
50 [self.tmr invalidate];
51 }
52
53 - (void)tmrMethod:(NSTimer *)timer {
54 [self getNextSlot];
55 }
56
57 - (void)didReceiveMemoryWarning {
58 [super didReceiveMemoryWarning];
59 // Dispose of any resources that can be recreated.
60 }
61
62 - (void)getNextSlot {
63 // TODO: Fix
64 /*
65 if(self.slotCounter == 0) {
66 [protocol getTime];
67 } else if(self.slotCounter == 1) {
68 [protocol getUsetime];
69 } else if(self.slotCounter == 2) {
70 [protocol getState];
71 } else if(self.slotCounter == 3) {
72 [protocol getSleep];
73 } else if(self.slotCounter == 4) {
74 [protocol getWake];
75 } else if(self.slotCounter == 5) {
76 [protocol getWalking];
77 }
78 */
79 self.slotCounter++;
80
81 if(self.slotCounter > self.slotCounterMax) {
82 self.slotCounter = self.slotCounterMin;
83 }
84 }
85
86 - (IBAction)btnEditState:(id)sender {
87 [self performSegueWithIdentifier:@"idSegueEditState" sender:self];
88 }
89
90 - (IBAction)btnEditTime:(id)sender {
91 [self performSegueWithIdentifier:@"idSegueEditTime" sender:self];
92 }
93
94 - (IBAction)btnEditSleep:(id)sender {
95 [self performSegueWithIdentifier:@"idSegueEditSleep" sender:self];
96 }
97
98 - (IBAction)btnEditWake:(id)sender {
99 [self performSegueWithIdentifier:@"idSegueEditWake" sender:self];
100 }
101
102 - (IBAction)btnEditWalking:(id)sender {
103 // TODO: Fix
104 if(stateCurrentWalking == false) {
105 //[protocol setWalking:true];
106 } else {
107 //[protocol setWalking:false];
108 }
109 }
110
111 - (IBAction)btnResetUsetime:(id)sender {
112 // TODO: Fix
113 //[protocol resetUsetime];
114 }
115
116 - (IBAction)btnUsetime:(id)sender {
117 [self performSegueWithIdentifier:@"idSegueUsetime" sender:self];
118 }
119
120 - (IBAction)btnCaseUnlock:(id)sender {
121 // TODO: Fix
122 //[protocol setUnlock];
123 }
124
125 - (void) protocolDidReceiveState:(NSString *)data text:(NSString *)text {
126 [currentState setText:text];
127 }
128
129 - (void) protocolDidReceiveTime:(NSString *) data {
130 [currentTime setText:data];
131 }
132
133 - (void) protocolDidReceiveSleepingBegin:(NSString *) data {
134 [currentSleep setText:data];
135 }
136
137 - (void) protocolDidReceiveSleepingEnd:(NSString *) data {
138 [currentWake setText:data];
139 }
140
141 - (void) protocolDidReceiveUsetime:(NSInteger) data {
142 int seconds = data % 60;
143 int minutes = (data / 60) % 60;
144 int hours = (int)data / 3600;
145
146 NSString *strUsetime = [NSString stringWithFormat:@"%02d:%02d:%02d",hours, minutes, seconds];
147 [currentUsetime setText:strUsetime];
148 }
149
150 - (void) protocolDidReceiveUsetimeSlot:(NSInteger) dataSlot dataStamp:(NSTimeInterval) dataStamp dataUsetime: (NSInteger) dataUsetime {
151
152 }
153
154 - (void) protocolDidReceiveWalking:(BOOL)data {
155 stateCurrentWalking = data;
156 NSString *strData = [NSString alloc];
157
158 if(stateCurrentWalking == false) {
159 strData = @"無効";
160 } else {
161 strData = @"有効";
162 }
163 [currentWalking setText:strData];
164 }
165
166
167 @end
1
2 /*
3
4 Copyright (c) 2013-2014 RedBearLab
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7
8 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11
12 */
13
14 #import <Foundation/Foundation.h>
15 #import "BLE.h"
16 #import <UIKit/UIKit.h>
17
18 @protocol BLEProtocolDelegate
19 @optional
20 - (void)protocolDidGetData:(NSString *)type data:(NSString *)data;
21 @required
22 @end
23
24 @interface BleProtocol : NSObject
25 @property (strong, nonatomic) BLE *ble;
26 @property (nonatomic,assign) id <BLEProtocolDelegate> delegate;
27 - (void) parseData:(unsigned char *) data length:(int) length;
28
29 /* APIs for query and read/write pins */
30 - (void)sendCommand: (uint8_t *) data Length:(uint8_t) length;
31 - (void)sendDisconnect;
32 - (void)putData:(NSString *)type data:(NSString *)data;
33 - (void)bleWriteRaw:(NSData*)data;
34
35 @end
1
2 /*
3
4 Copyright (c) 2013-2014 RedBearLab
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7
8 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11
12 */
13
14 #import "BleProtocol.h"
15 #import "jacket_test_ios-Swift.h"
16
17 @implementation BleProtocol
18 @synthesize ble;
19
20 //#define PROT_DEBUG
21
22 -(void)parseData:(unsigned char *) data length:(int) length
23 {
24 NSString *dataStringRaw = [NSString stringWithCString: (const char *)data encoding:NSUTF8StringEncoding];
25 dataStringRaw = [dataStringRaw substringToIndex:length];
26
27 NSLog(@"[BleProtocol parseData] %@",dataStringRaw);
28
29 /* for iot Demo */
30 NSArray *parsed = [[SenserData sheardInstance] parseData:dataStringRaw];
31 if(parsed != nil){
32 NSString *type = parsed[2];
33 NSString *payload = parsed[3];
34 [[SenserData sheardInstance] setData:type data:payload];
35 }
36 /* for iot Demo end */
37
38
39 NSArray *dataStringRawSplit = [[NSMutableArray alloc]initWithArray: [dataStringRaw componentsSeparatedByString:@"@"]];
40
41 for(id object in dataStringRawSplit) {
42 NSString * dataString = object;
43 NSInteger dataStringLength = [object length];
44
45 NSLog(@"%@",dataString);
46
47 if([dataString length] < 2) {
48 dataString = [dataString stringByAppendingString:@"@"];
49 }
50
51 if([dataString length] > 1) {
52 if(![[dataString substringWithRange:NSMakeRange([dataString length] - 1, 1)] isEqualToString: @"?"]) {
53 if([dataString hasPrefix:@"ii"]) {
54 NSString *strData = [NSString stringWithFormat:@"%@",
55 [dataString substringWithRange:NSMakeRange(2, dataStringLength - 2)]];
56 [[self delegate] protocolDidGetData:@"infoDeviceId" data:strData];
57 } else if([dataString hasPrefix:@"it"]) {
58 NSString *strData = [NSString stringWithFormat:@"%@",
59 [dataString substringWithRange:NSMakeRange(2, dataStringLength - 2)]];
60 [[self delegate] protocolDidGetData:@"infoDeviceType" data:strData];
61 } else if([dataString hasPrefix:@"im"]) {
62 NSString *strData = [NSString stringWithFormat:@"%@",
63 [dataString substringWithRange:NSMakeRange(2, dataStringLength - 2)]];
64 [[self delegate] protocolDidGetData:@"infoDeviceModel" data:strData];
65 } else if([dataString hasPrefix:@"io"]) {
66 NSString *strData = [NSString stringWithFormat:@"%@",
67 [dataString substringWithRange:NSMakeRange(2, dataStringLength - 2)]];
68 [[self delegate] protocolDidGetData:@"infoDeviceOs" data:strData];
69 } else if([dataString hasPrefix:@"ip"]) {
70 NSString *strData = [NSString stringWithFormat:@"%@",
71 [dataString substringWithRange:NSMakeRange(2, dataStringLength - 2)]];
72 [[self delegate] protocolDidGetData:@"infoDevicePin" data:strData];
73 } else if([dataString hasPrefix:@"ki"]) {
74 NSString *strData = [NSString stringWithFormat:@"%@",
75 [dataString substringWithRange:NSMakeRange(2, dataStringLength - 2)]];
76 [[self delegate] protocolDidGetData:@"readDeviceId" data:strData];
77 } else if([dataString hasPrefix:@"kt"]) {
78 NSString *strData = [NSString stringWithFormat:@"%@",
79 [dataString substringWithRange:NSMakeRange(2, dataStringLength - 2)]];
80 [[self delegate] protocolDidGetData:@"readDeviceType" data:strData];
81 } else if([dataString hasPrefix:@"km"]) {
82 NSString *strData = [NSString stringWithFormat:@"%@",
83 [dataString substringWithRange:NSMakeRange(2, dataStringLength - 2)]];
84 [[self delegate] protocolDidGetData:@"readDeviceModel" data:strData];
85 } else if([dataString hasPrefix:@"ko"]) {
86 NSString *strData = [NSString stringWithFormat:@"%@",
87 [dataString substringWithRange:NSMakeRange(2, dataStringLength - 2)]];
88 [[self delegate] protocolDidGetData:@"readDeviceOs" data:strData];
89 } else if([dataString hasPrefix:@"kp"]) {
90 NSString *strData = [NSString stringWithFormat:@"%@",
91 [dataString substringWithRange:NSMakeRange(2, dataStringLength - 2)]];
92 [[self delegate] protocolDidGetData:@"readDevicePin" data:strData];
93 } else if([dataString hasPrefix:@"ji"]) {
94 [[self delegate] protocolDidGetData:@"writeDeviceId" data:@"OK"];
95 } else if([dataString hasPrefix:@"jm"]) {
96 [[self delegate] protocolDidGetData:@"writeDeviceModel" data:@"OK"];
97 } else if([dataString hasPrefix:@"jt"]) {
98 [[self delegate] protocolDidGetData:@"writeDeviceType" data:@"OK"];
99 } else if([dataString hasPrefix:@"jo"]) {
100 [[self delegate] protocolDidGetData:@"writeDeviceOs" data:@"OK"];
101 } else if([dataString hasPrefix:@"jp"]) {
102 [[self delegate] protocolDidGetData:@"writeDevicePin" data:@"OK"];
103 } else if([dataString hasPrefix:@"rm"]) {
104 if(dataStringLength == 3) {
105 NSString *strMotor = [dataString substringWithRange:NSMakeRange(2,1)];
106 NSString *strMotorText = @"";
107 if([strMotor isEqualToString:@"0"]) {
108 strMotorText = @"OFF";
109 } else if([strMotor isEqualToString:@"1"]) {
110 strMotorText = @"ON0";
111 } else if([strMotor isEqualToString:@"2"]) {
112 strMotorText = @"ON2";
113 }
114 [[self delegate] protocolDidGetData:@"readMotor" data:strMotorText];
115 }
116 } else if([dataString hasPrefix:@"wm"]) {
117 [[self delegate] protocolDidGetData:@"writeMotor" data:@"OK"];
118 } else if([dataString hasPrefix:@"ws"]) {
119 [[self delegate] protocolDidGetData:@"writeSound" data:@"OK"];
120 } else if([dataString hasPrefix:@"ep"]) {
121 if(dataStringLength == 3) {
122 NSString *strData = [dataString substringWithRange:NSMakeRange(2,1)];
123 [[self delegate] protocolDidGetData:@"eepromWriteProtect" data:strData];
124 }
125 } else if([dataString hasPrefix:@"fi"]) {
126 if(dataStringLength == 3) {
127 NSString *strData = [dataString substringWithRange:NSMakeRange(2,1)];
128 [[self delegate] protocolDidGetData:@"firmwareImageSelect" data:strData];
129 }
130 } else if([dataString hasPrefix:@"fc"]) {
131 [[self delegate] protocolDidGetData:@"firmwareBufferClear" data:@"OK"];
132 } else if([dataString hasPrefix:@"fw"]) {
133 if(dataStringLength == 4) {
134 NSString *strData = [dataString substringWithRange:NSMakeRange(2,2)];
135 [[self delegate] protocolDidGetData:@"firmwareFlashWrite" data:strData];
136 }
137 } else if([dataString hasPrefix:@"fe"]) {
138 if(dataStringLength == 3) {
139 NSString *strData = [dataString substringWithRange:NSMakeRange(2,1)];
140 NSString *strDataText = @"";
141 if([strData isEqualToString:@"0"]) {
142 strDataText = @"0";
143 } else if([strData isEqualToString:@"1"]) {
144 strDataText = @"1";
145 }
146 [[self delegate] protocolDidGetData:@"firmwareFlashErase" data:strDataText];
147 }
148 } else if([dataString hasPrefix:@"sr"]) {
149 [[self delegate] protocolDidGetData:@"systemReset" data:@"OK"];
150 } else if([dataString hasPrefix:@"su"]) {
151 [[self delegate] protocolDidGetData:@"systemResetInBootloader" data:@"OK"];
152 } else if(dataStringLength == 1) {
153 //data write success
154 [[self delegate] protocolDidGetData:@"firmwareBufferWrite" data:@"OK"];
155 } else {
156 //unknown data received
157 [[self delegate] protocolDidGetData:@"unknown" data:@"unknown"];
158 }
159 } else if([dataString hasPrefix:@"x"]) {
160 //error
161 [[self delegate] protocolDidGetData:@"firmwareBufferWrite" data:@"NG"];
162 }
163 }
164 }
165 }
166
167 - (void)sendCommand: (uint8_t *) data Length:(uint8_t) length
168 {
169 uint8_t buf[length+1];
170 memcpy(&buf[0], data, length);
171 uint8_t len = length+1;
172 buf[len - 1] = '@';
173
174 NSData *nsData = [[NSData alloc] initWithBytes:buf length:len];
175 [ble write:nsData];
176 }
177
178 - (void)sendDisconnect {
179 NSString *strData = @"sd@";
180
181 NSData *nsData = [strData dataUsingEncoding:NSUTF8StringEncoding];
182 [ble write:nsData];
183 }
184
185 - (void)putData:(NSString *)type data:(NSString *)data {
186 NSString *blePut = nil;
187 if([type isEqualToString:@"infoDeviceId"]) {
188 NSString *bleCommand = @"ii";
189 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
190 } else if([type isEqualToString:@"infoDeviceType"]) {
191 NSString *bleCommand = @"it";
192 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
193 } else if([type isEqualToString:@"infoDeviceModel"]) {
194 NSString *bleCommand = @"im";
195 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
196 } else if([type isEqualToString:@"infoDeviceOs"]) {
197 NSString *bleCommand = @"io";
198 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
199 } else if([type isEqualToString:@"infoDevicePin"]) {
200 NSString *bleCommand = @"ip";
201 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
202 } else if([type isEqualToString:@"readDeviceId"]) {
203 NSString *bleCommand = @"ki";
204 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
205 } else if([type isEqualToString:@"readDeviceType"]) {
206 NSString *bleCommand = @"kt";
207 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
208 } else if([type isEqualToString:@"readDeviceModel"]) {
209 NSString *bleCommand = @"km";
210 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
211 } else if([type isEqualToString:@"readDeviceOs"]) {
212 NSString *bleCommand = @"ko";
213 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
214 } else if([type isEqualToString:@"readDevicePin"]) {
215 NSString *bleCommand = @"kp";
216 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
217 } else if([type isEqualToString:@"writeDeviceId"]) {
218 NSString *bleCommand = @"ji";
219 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
220 } else if([type isEqualToString:@"writeDeviceModel"]) {
221 NSString *bleCommand = @"jm";
222 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
223 } else if([type isEqualToString:@"writeDeviceType"]) {
224 NSString *bleCommand = @"jt";
225 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
226 } else if([type isEqualToString:@"writeDeviceOs"]) {
227 NSString *bleCommand = @"jo";
228 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
229 } else if([type isEqualToString:@"writeDevicePin"]) {
230 NSString *bleCommand = @"jp";
231 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
232 } else if([type isEqualToString:@"readMotor"]) {
233 NSString *bleCommand = @"rm";
234 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
235 } else if([type isEqualToString:@"writeMotor"]) {
236 NSString *bleCommand = @"wm";
237 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
238 } else if([type isEqualToString:@"writeSound"]) {
239 NSString *bleCommand = @"ws";
240 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
241 } else if([type isEqualToString:@"eepromWriteProtect"]) {
242 NSString *bleCommand = @"ep";
243 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
244 } else if([type isEqualToString:@"firmwareImageSelect"]) {
245 NSString *bleCommand = @"fi";
246 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
247 } else if([type isEqualToString:@"firmwareBufferClear"]) {
248 NSString *bleCommand = @"fc";
249 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
250 } else if([type isEqualToString:@"firmwareFlashErase"]) {
251 NSString *bleCommand = @"fe";
252 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
253 } else if([type isEqualToString:@"firmwareFlashWrite"]) {
254 NSString *bleCommand = @"fw";
255 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
256 } else if([type isEqualToString:@"systemReset"]) {
257 NSString *bleCommand = @"sr";
258 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
259 } else if([type isEqualToString:@"systemResetInBootloader"]) {
260 NSString *bleCommand = @"su";
261 blePut = [NSString stringWithFormat:@"%@%@@",bleCommand,[self safeNil:data]];
262 }
263
264 if(blePut) {
265 NSLog(@"BLE_WRITE: %@", blePut);
266 NSData *nsData = [blePut dataUsingEncoding:NSUTF8StringEncoding];
267 [ble write:nsData];
268 } else {
269 NSLog(@"BLE_WRITE: ERROR %@ UNKNOWN", type);
270 }
271 }
272
273 - (void)bleWriteRaw:(NSData*)data {
274 [ble write:data];
275 }
276
277 - (NSString *)safeNil:(NSString *)data {
278 if(data == nil) return @"";
279 return data;
280 }
281
282 @end
1 //
2 // DetailViewTableViewCell.h
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2016/04/27.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10
11 @interface BleSearchResultTableViewCell : UITableViewCell {
12 IBOutlet UILabel *lblUuidTapped;
13 IBOutlet UILabel *lblRssiTapped;
14 IBOutlet UILabel *lblNameTapped;
15 }
16
17 @property (strong, nonatomic) UILabel *lblUuid;
18 @property (strong, nonatomic) UILabel *lblRssi;
19 @property (strong, nonatomic) UILabel *lblName;
20
21 @end
1 //
2 // DetailViewTableViewCell.m
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2016/04/27.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "BleSearchResultTableViewCell.h"
10
11 @implementation BleSearchResultTableViewCell
12
13 - (void)awakeFromNib {
14 [super awakeFromNib];
15 // Initialization code
16 }
17
18 - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
19 [super setSelected:selected animated:animated];
20
21 // Configure the view for the selected state
22 }
23
24 @end
1 //
2 // BleSearchResultTableViewController.h
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2016/04/27.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10 #import "BLE.h"
11 #import "BleProtocol.h"
12
13 @interface BleSearchResultTableViewController : UITableViewController
14
15 @property (strong, nonatomic) BLE *ble;
16 @property (strong, nonatomic) BleProtocol *protocol;
17 @property (strong, nonatomic) NSMutableArray *BLEDevices;
18 @property (strong, nonatomic) NSMutableArray *BLEDevicesRssi;
19 @property (strong, nonatomic) NSMutableArray *BLEDevicesName;
20
21 @end
1 //
2 // BleSearchResultTableViewController.m
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2016/04/27.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "BleSearchResultTableViewController.h"
10 #import "BleSearchResultTableViewCell.h"
11
12 @interface BleSearchResultTableViewController ()
13
14 @end
15
16 @implementation BleSearchResultTableViewController
17
18 @synthesize ble;
19 @synthesize BLEDevicesRssi;
20
21 - (void)viewDidLoad {
22 [super viewDidLoad];
23
24 // Uncomment the following line to preserve selection between presentations.
25 // self.clearsSelectionOnViewWillAppear = NO;
26
27 // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
28 // self.navigationItem.rightBarButtonItem = self.editButtonItem;
29
30 self.BLEDevicesRssi = [NSMutableArray arrayWithArray:ble.peripheralsRssi];
31 }
32
33 - (void)didReceiveMemoryWarning {
34 [super didReceiveMemoryWarning];
35 // Dispose of any resources that can be recreated.
36 }
37
38 -(void) connectionTimer:(NSTimer *)timer
39 {
40 [self.BLEDevices removeAllObjects];
41 [self.BLEDevicesRssi removeAllObjects];
42 [self.BLEDevicesName removeAllObjects];
43
44 if (ble.peripherals.count > 0)
45 {
46 for (int i = 0; i < ble.peripherals.count; i++)
47 {
48 CBPeripheral *p = [ble.peripherals objectAtIndex:i];
49 NSNumber *n = [ble.peripheralsRssi objectAtIndex:i];
50 NSString *name = [[ble.peripherals objectAtIndex:i] name];
51
52 if (p.identifier.UUIDString != NULL)
53 {
54 [self.BLEDevices insertObject:p.identifier.UUIDString atIndex:i];
55 [self.BLEDevicesRssi insertObject:n atIndex:i];
56
57 if (name != nil)
58 {
59 [self.BLEDevicesName insertObject:name atIndex:i];
60 }
61 else
62 {
63 [self.BLEDevicesName insertObject:@"RedBear Device" atIndex:i];
64 }
65 }
66 else
67 {
68 [self.BLEDevices insertObject:@"NULL" atIndex:i];
69 [self.BLEDevicesRssi insertObject:@"0" atIndex:i];
70 [self.BLEDevicesName insertObject:@"RedBear Device" atIndex:i];
71 }
72 }
73 }
74 else
75 {
76 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
77 message:@"No BLE Device(s) found."
78 delegate:nil
79 cancelButtonTitle:@"OK"
80 otherButtonTitles:nil];
81 [alert show];
82 }
83
84 [self.tableView reloadData];
85 }
86
87 #pragma mark - Table view data source
88
89 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
90 // Return the number of sections.
91 return 1;
92 }
93
94 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
95 // Return the number of rows in the section.
96 return self.BLEDevices.count;
97 }
98
99 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
100 {
101 static NSString *tableIdentifier = @"cell_uuid";
102 BleSearchResultTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:tableIdentifier forIndexPath:indexPath];
103
104 // Configure the cell...
105 UIFont *newFont = [UIFont fontWithName:@"Arial" size:13.5];
106
107 cell.lblUuid.font = newFont;
108 cell.lblUuid.text = [self.BLEDevices objectAtIndex:indexPath.row];
109
110 newFont = [UIFont fontWithName:@"Arial" size:11.0];
111 cell.lblRssi.font = newFont;
112 NSMutableString *rssiString = [NSMutableString stringWithFormat:@"RSSI : %@", [self.BLEDevicesRssi objectAtIndex:indexPath.row]];
113 cell.lblRssi.text = rssiString;
114
115 newFont = [UIFont fontWithName:@"Arial" size:13.0];
116 cell.lblName.font = newFont;
117 cell.lblName.text = [self.BLEDevicesName objectAtIndex:indexPath.row];
118
119 return cell;
120 }
121
122 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
123 {
124 if(ble.isConnected) {
125 [self.protocol sendDisconnect];
126 }
127 [ble connectPeripheral:[ble.peripherals objectAtIndex:indexPath.row]];
128 }
129
130 @end
1 //
2 // ViewController.h
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2016/04/27.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10 #import "BLE.h"
11 #import "BleProtocol.h"
12
13 @interface BleSearchViewController : UIViewController <BLEDelegate>
14 {
15 IBOutlet UIActivityIndicatorView *activityScanning;
16 IBOutlet UIButton *btnConnect;
17 IBOutlet UIButton *btnConnectLast;
18 IBOutlet UILabel *lblVersion;
19 BOOL showAlert;
20 bool isFindingLast;
21 }
22
23 @property (strong, nonatomic) BLE *ble;
24 @property (strong, nonatomic) BleProtocol *protocol;
25 @property (strong, nonatomic) NSMutableArray *mDevices;
26 @property (strong, nonatomic) NSMutableArray *mDevicesName;
27 @property (strong,nonatomic) NSString *lastUUID;
28
29 - (IBAction)btnConnectClicked:(id)sender;
30 - (IBAction)lastClick:(id)sender;
31 - (void)bleDidConnect;
32 - (void)bleDidDisconnect;
33 - (void)bleDidReceiveData:(unsigned char *)data length:(int)length;
34 - (void)bleDidUpdateRSSI:(NSNumber *) rssi;
35 - (NSString *)getUUIDString:(CFUUIDRef)ref;
36
37 @end
38
1 //
2 // BleSearchViewController.m
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2016/04/27.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "BleSearchViewController.h"
10 #import "BleControl.h"
11 #import "BleSearchResultTableViewController.h"
12 #import "SettingsController.h"
13 #import "Operation.h"
14 #import "jacket_test_ios-Swift.h"
15
16 @interface BleSearchViewController ()
17
18 @end
19
20 NSString * const UUIDPrefKey = @"UUIDPrefKey";
21
22 @implementation BleSearchViewController
23 @synthesize ble;
24 @synthesize protocol;
25 BleControl *cv;
26
27 - (void)viewDidLoad {
28 [super viewDidLoad];
29 // Do any additional setup after loading the view, typically from a nib.
30
31 ble = [[BLE alloc] init];
32 [ble controlSetup];
33 ble.delegate = self;
34
35 self.mDevices = [[NSMutableArray alloc] init];
36 self.mDevicesName = [[NSMutableArray alloc] init];
37
38 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"firstLaunch"])
39 {
40 [[NSUserDefaults standardUserDefaults] setObject:@"" forKey:UUIDPrefKey];
41 }
42
43 //Retrieve saved UUID from system
44 self.lastUUID = [[NSUserDefaults standardUserDefaults] objectForKey:UUIDPrefKey];
45 if ([self.lastUUID isEqualToString:@""])
46 {
47 [btnConnectLast setEnabled:NO];
48 }
49 else
50 {
51 [btnConnectLast setEnabled:YES];
52 }
53
54 protocol = [[BleProtocol alloc] init];
55 protocol.ble = ble;
56 }
57
58 - (void)didReceiveMemoryWarning {
59 [super didReceiveMemoryWarning];
60 // Dispose of any resources that can be recreated.
61 }
62
63 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
64 {
65 if ([[segue identifier] isEqualToString:@"idSegueBleDeviceList"])
66 {
67 BleSearchResultTableViewController *vc = [segue destinationViewController];
68 vc.BLEDevices = self.mDevices;
69 vc.BLEDevicesName = self.mDevicesName;
70 vc.ble = ble;
71 vc.protocol = protocol;
72 }
73 else if ([[segue identifier] isEqualToString:@"idSegueBleDevice"])
74 {
75 cv = [segue destinationViewController];
76 cv.ble = ble;
77 cv.protocol = protocol;
78 }
79 }
80
81 - (void)connectionTimer:(NSTimer *)timer
82 {
83 showAlert = YES;
84 [btnConnect setEnabled:YES];
85
86 self.lastUUID = [[NSUserDefaults standardUserDefaults] objectForKey:UUIDPrefKey];
87
88 if ([self.lastUUID isEqualToString:@""])
89 {
90 [btnConnectLast setEnabled:NO];
91 }
92 else
93 {
94 [btnConnectLast setEnabled:YES];
95 }
96
97 if (ble.peripherals.count > 0)
98 {
99 if(isFindingLast)
100 {
101 int i;
102 for (i = 0; i < ble.peripherals.count; i++)
103 {
104 CBPeripheral *p = [ble.peripherals objectAtIndex:i];
105
106 if (p.identifier.UUIDString != NULL)
107 {
108 //Comparing UUIDs and call connectPeripheral is matched
109 if([self.lastUUID isEqualToString:p.identifier.UUIDString])
110 {
111 showAlert = NO;
112 [ble connectPeripheral:p];
113 }
114 }
115 }
116 }
117 else
118 {
119 [self.mDevices removeAllObjects];
120 [self.mDevicesName removeAllObjects];
121
122 int i;
123 for (i = 0; i < ble.peripherals.count; i++)
124 {
125 CBPeripheral *p = [ble.peripherals objectAtIndex:i];
126
127 if (p.identifier.UUIDString != NULL)
128 {
129 [self.mDevices insertObject:p.identifier.UUIDString atIndex:i];
130 if (p.name != nil) {
131 [self.mDevicesName insertObject:p.name atIndex:i];
132 } else {
133 [self.mDevicesName insertObject:@"RedBear Device" atIndex:i];
134 }
135 }
136 else
137 {
138 [self.mDevices insertObject:@"NULL" atIndex:i];
139 [self.mDevicesName insertObject:@"RedBear Device" atIndex:i];
140 }
141 }
142 showAlert = NO;
143 [self performSegueWithIdentifier:@"idSegueBleDeviceList" sender:self];
144 }
145 }
146
147 if (showAlert == YES) {
148 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
149 message:@"No BLE Device(s) found."
150 delegate:nil
151 cancelButtonTitle:@"OK"
152 otherButtonTitles:nil];
153 [alert show];
154 }
155
156 [activityScanning stopAnimating];
157 }
158
159 - (IBAction)btnConnectClicked:(id)sender
160 {
161 if (ble.activePeripheral)
162 if(ble.activePeripheral.state == CBPeripheralStateConnected)
163 {
164 [[ble CM] cancelPeripheralConnection:[ble activePeripheral]];
165 return;
166 }
167
168 if (ble.peripherals)
169 ble.peripherals = nil;
170
171 [btnConnect setEnabled:false];
172 [btnConnectLast setEnabled:NO];
173 [ble findBLEPeripherals:3];
174
175 [NSTimer scheduledTimerWithTimeInterval:(float)3.0 target:self selector:@selector(connectionTimer:) userInfo:nil repeats:NO];
176
177 isFindingLast = false;
178 [activityScanning startAnimating];
179 }
180
181 - (IBAction)lastClick:(id)sender {
182 if (ble.peripherals) {
183 ble.peripherals = nil;
184 }
185
186 [btnConnect setEnabled:false];
187 [btnConnectLast setEnabled:NO];
188 [ble findBLEPeripherals:3];
189
190 [NSTimer scheduledTimerWithTimeInterval:(float)3.0 target:self selector:@selector(connectionTimer:) userInfo:nil repeats:NO];
191
192 isFindingLast = true;
193 [activityScanning startAnimating];
194 }
195
196 - (void) bleDidConnect
197 {
198 NSLog(@"->DidConnect");
199
200 self.lastUUID = ble.activePeripheral.identifier.UUIDString;
201 [[NSUserDefaults standardUserDefaults] setObject:self.lastUUID forKey:UUIDPrefKey];
202 [[NSUserDefaults standardUserDefaults] synchronize];
203
204 self.lastUUID = [[NSUserDefaults standardUserDefaults] objectForKey:UUIDPrefKey];
205 if ([self.lastUUID isEqualToString:@""]) {
206 [btnConnectLast setEnabled:NO];
207 } else {
208 [btnConnectLast setEnabled:YES];
209 }
210
211 [activityScanning stopAnimating];
212
213 [self populatePcbInfo];
214
215 [SettingsController show:(NSString *)protocol navigationController:self.navigationController];
216 }
217
218 - (void)bleDidDisconnect
219 {
220 NSLog(@"->DidDisconnect");
221
222 [activityScanning stopAnimating];
223 [self.navigationController popToRootViewControllerAnimated:true];
224 }
225
226 - (void)populatePcbInfo {
227 if([Operation sharedOperation].pcbDeviceId == nil) {
228 [protocol putData:@"infoDeviceId" data:nil];
229 } else if([Operation sharedOperation].pcbDeviceType == nil) {
230 [protocol putData:@"infoDeviceType" data:nil];
231 } else if([Operation sharedOperation].pcbDeviceModel == nil) {
232 [protocol putData:@"infoDeviceModel" data:nil];
233 } else if([Operation sharedOperation].pcbDeviceOs == nil) {
234 [protocol putData:@"infoDeviceOs" data:nil];
235 }
236 }
237
238 - (void) bleDidReceiveData:(unsigned char *)data length:(int)length
239 {
240
241 NSLog(@"data!!!%s", data);
242
243 for(int i = 0; i < length; i++) {
244 if((data[i] < 32) || (data[i] > 127)) {
245 data[i] = ' ';
246 }
247 }
248 NSString* dataString = [NSString stringWithCString: (const char *)data encoding:NSUTF8StringEncoding];
249 dataString = [dataString substringToIndex:length];
250
251
252 NSLog(@"->DidReceiveData- %@",dataString);
253
254 if([dataString hasPrefix:@"ii"]) {
255 [Operation sharedOperation].pcbDeviceId = [dataString substringWithRange:NSMakeRange(2, [dataString length] - 3)];
256 [self populatePcbInfo];
257 } else if ([dataString hasPrefix:@"it"]) {
258 [Operation sharedOperation].pcbDeviceType = [dataString substringWithRange:NSMakeRange(2, [dataString length] - 3)];
259 [self populatePcbInfo];
260 } else if ([dataString hasPrefix:@"im"]) {
261 [Operation sharedOperation].pcbDeviceModel = [dataString substringWithRange:NSMakeRange(2, [dataString length] - 3)];
262 [self populatePcbInfo];
263 } else if ([dataString hasPrefix:@"io"]) {
264 [Operation sharedOperation].pcbDeviceOs = [dataString substringWithRange:NSMakeRange(2, [dataString length] - 3)];
265 [self populatePcbInfo];
266 }
267
268 [protocol parseData:data length:length];
269 /* for iot Demo */
270 [[Caller sheardInstance] proximityNofitication :[SenserData sheardInstance].proximity ];
271 /* for iot Demo end */
272 }
273
274 - (void) bleDidUpdateRSSI:(NSNumber *) rssi
275 {
276 }
277
278 - (NSString *)getUUIDString:(CFUUIDRef)ref {
279 NSString *str = [NSString stringWithFormat:@"%@", ref];
280 return [[NSString stringWithFormat:@"%@", str] substringWithRange:NSMakeRange(str.length - 36, 36)];
281 }
282
283 @end
1 //
2 // caller.swift
3 // jacket_test_ios
4 //
5 // Created by USER on 2017/10/11.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 import Foundation
10 import UIKit
11 import UserNotifications
12 class Caller:NSObject{
13 public static let sheardInstance:Caller = Caller()
14
15 public func proximityNofitication(_ data:Int){
16 if(data > 100 ){return}
17 if #available(iOS 10.0, *) {
18 NSLog("yobareta");
19 UserNofitication.sharedInstance.easyNofitication(
20 /* nofitication detail */
21 identifier : "nofity",
22 title : "データが届きました",
23 body : String(data) + "cm",
24 actions : [
25 UNNotificationAction(
26 identifier: "possitive",
27 title: "",
28 options:[])], completionHandler: ({(Error)->Void in
29
30 }),
31
32 /* response callback */
33 response : UNResponseManager.sharedInstance.setResponse(identifier: "nofity") {(_ actionIdentifier:String) in
34 switch actionIdentifier {
35 case "positive":
36
37
38 break
39 case UNNotificationDismissActionIdentifier:
40 /* 選択せずにnofiticationを消去の場合*/
41 break
42 case UNNotificationDefaultActionIdentifier:
43 /* 選択せずにアプリ起動場合*/
44 break
45 default:
46 break
47 }
48 })
49 } else {
50 // Fallback on earlier versions
51 }
52 }
53
54 public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
55
56 if #available(iOS 10.0, *) {
57 let center = UNUserNotificationCenter.current()
58 center.requestAuthorization(options: [.alert], completionHandler: { (granted, error) in
59 if error != nil {
60 print(error?.localizedDescription)
61 return
62 }
63 })
64 }
65
66 return true
67 }
68 }
69
1 //
2 // caller.swift
3 // jacket_test_ios
4 //
5 // Created by USER on 2017/10/11.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 import Foundation
10 class Caller{
11 UserNofitication.sharedInstance.easyNofitication(
12 /* nofitication detail */
13 identifier : "accident",
14 title : DefaultText.AccidentTitle.rawValue,
15 body : DefaultText.AccidentBody.rawValue,
16 actions : [
17 UNNotificationAction(
18 identifier:"negative",
19 title: DefaultText.AccidentNegativeButton.rawValue,
20 options: []),
21 UNNotificationAction(
22 identifier: "possitive",
23 title: DefaultText.AccidentPositiveButton.rawValue,
24 options:[])], completionHandler: ({(Error)->Void in
25
26 /* 応答がなければ アクシデントとみなす */
27
28 if(UserState.instance._hasAccident)!{
29 _ = Timer.scheduledTimer(
30 timeInterval: 120.0,
31 target : self,
32 selector : #selector(core_functions.sharedInstance.accidentHappend),
33 userInfo : nil,
34 repeats : false ).fire()
35 }
36
37
38 }),
39
40 /* response callback */
41 response : UNResponseManager.sharedInstance.setResponse(identifier: "accident") {(_ actionIdentifier:String) in
42
43 NSLog("accident happend")
44 switch actionIdentifier {
45 case "negative":
46 core_functions.sharedInstance.accidentHappend()
47 break
48 case "positive":
49 core_functions.sharedInstance.accidentCancel()
50 break
51 case UNNotificationDismissActionIdentifier:
52 /* 選択せずにnofiticationを消去の場合*/
53 break
54 case UNNotificationDefaultActionIdentifier:
55 /* 選択せずにアプリ起動場合*/
56 break
57 default:
58 break
59 }
60 })
61 }
62 }
1 //
2 // DemoViewController.swift
3 // jacket_test_ios
4 //
5 // Created by USER on 2017/10/11.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 import UIKit
10
11 class DemoViewController: UIViewController {
12
13 override func viewDidLoad() {
14 super.viewDidLoad()
15
16 // Do any additional setup after loading the view.
17 }
18
19 override func didReceiveMemoryWarning() {
20 super.didReceiveMemoryWarning()
21 // Dispose of any resources that can be recreated.
22 }
23
24
25 /*
26 // MARK: - Navigation
27
28 // In a storyboard-based application, you will often want to do a little preparation before navigation
29 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
30 // Get the new view controller using segue.destinationViewController.
31 // Pass the selected object to the new view controller.
32 }
33 */
34
35 }
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 <dict>
5 <key>CFBundleDevelopmentRegion</key>
6 <string>en</string>
7 <key>CFBundleDisplayName</key>
8 <string>jacket_test_ios</string>
9 <key>CFBundleExecutable</key>
10 <string>$(EXECUTABLE_NAME)</string>
11 <key>CFBundleIdentifier</key>
12 <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13 <key>CFBundleInfoDictionaryVersion</key>
14 <string>6.0</string>
15 <key>CFBundleName</key>
16 <string>$(PRODUCT_NAME)</string>
17 <key>CFBundlePackageType</key>
18 <string>APPL</string>
19 <key>CFBundleShortVersionString</key>
20 <string>0.1</string>
21 <key>CFBundleSignature</key>
22 <string>????</string>
23 <key>CFBundleVersion</key>
24 <string>1</string>
25 <key>LSRequiresIPhoneOS</key>
26 <true/>
27 <key>NSAppTransportSecurity</key>
28 <dict>
29 <key>NSAllowsArbitraryLoads</key>
30 <true/>
31 </dict>
32 <key>UILaunchStoryboardName</key>
33 <string>LaunchScreen</string>
34 <key>UIMainStoryboardFile</key>
35 <string>Main</string>
36 <key>UIRequiredDeviceCapabilities</key>
37 <array>
38 <string>armv7</string>
39 </array>
40 <key>UISupportedInterfaceOrientations</key>
41 <array>
42 <string>UIInterfaceOrientationPortrait</string>
43 </array>
44 <key>UISupportedInterfaceOrientations~ipad</key>
45 <array>
46 <string>UIInterfaceOrientationPortrait</string>
47 <string>UIInterfaceOrientationPortraitUpsideDown</string>
48 <string>UIInterfaceOrientationLandscapeLeft</string>
49 <string>UIInterfaceOrientationLandscapeRight</string>
50 </array>
51 </dict>
52 </plist>
1 //
2 // NSData+NSString.h
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/06/07.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <Foundation/Foundation.h>
10
11 @interface NSData (NSString)
12
13 - (NSString *)toString;
14
15 @end
1 //
2 // NSData+NSString.m
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2017/06/07.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import "NSData+NSString.h"
10
11 @implementation NSData (NSString)
12
13 - (NSString *)toString
14 {
15 Byte *dataPointer = (Byte *)[self bytes];
16 NSMutableString *result = [NSMutableString stringWithCapacity:0];
17 NSUInteger index;
18 for (index = 0; index < [self length]; index++)
19 {
20 [result appendFormat:@"0x%02x,", dataPointer[index]];
21 }
22 return result;
23 }
24
25 @end
1 //
2 // Data.swift
3 // jacket_test_ios
4 //
5 // Created by USER on 2017/10/11.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 import Foundation
10
11 class SenserData:NSObject{
12 public static let sheardInstance:SenserData = SenserData()
13
14 public var data:String = "1"
15 public var proximity:Int = 0
16
17
18 public func setData(_ type:String,data:String){
19 switch type {
20 case "03":
21 proximity = Int(data, radix: 16)!
22 break
23 default:
24 break
25 }
26 }
27
28 public func parseData(_ data:String)->[String]?{
29 if(5 > data.count ){return nil}
30
31 var parsed = [String]()
32 parsed.append(substr(data,start: 0, end: 4))
33 NSLog(substr(data,start: 0, end: 4))
34 parsed.append(substr(data,start: 4, end: 8))
35 NSLog(substr(data,start: 4, end: 8))
36 parsed.append(substr(data,start: 8, end: 10))
37 NSLog(substr(data,start: 8, end: 10))
38 parsed.append(substr(data,start: 10, end: 14))
39 parsed.append(substr(data,start: 14, end: 16))
40
41 return parsed
42 }
43
44 public func lessThan(_ val:Int , of:Int)->Int?{
45 if(val < of){ return of }
46 return nil
47 }
48 private func substr(_ str:String,start:Int,end:Int)->String{
49 let startIndex = str.index(str.startIndex, offsetBy: start)
50 let endIndex = str.index(str.startIndex, offsetBy: end)
51 return str.substring(with: startIndex..<endIndex)
52 }
53 }
1 //
2 // UserNofiticationManager.swift
3 // ko-seigen
4 //
5 // Created by USER on 2017/10/04.
6 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 import Foundation
10 //
11 // UNNofiticationResponse.swift
12 // ko-seigen
13 //
14 // Created by USER on 2017/10/04.
15 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
16 //
17
18 import Foundation
19 import UserNotifications
20
21 class UNResponseManager:NSObject, UNUserNotificationCenterDelegate{
22
23 static let sharedInstance = UNResponseManager();
24 private var Response:[String:((_ actionIdentifier:String) -> Void )] = [:]
25
26 public func setResponse( identifier:String,response:@escaping ((_ actionIdentifier:String) -> Void ))
27 ->UNResponseManager{
28 if(Response[identifier] == nil){
29 Response[identifier] = response
30 }
31 return self
32 }
33
34 @available(iOS 10.0, *)
35 func userNotificationCenter(_ center: UNUserNotificationCenter,
36 willPresent notification: UNNotification,
37 withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
38 completionHandler([.alert,.sound])
39 NSLog("called")
40 }
41
42 @available(iOS 10.0, *)
43 func userNotificationCenter(_ center: UNUserNotificationCenter,
44 didReceive response: UNNotificationResponse,
45 withCompletionHandler completionHandler: @escaping () -> Void) {
46
47 let id = response.notification.request.content.categoryIdentifier
48 if(Response[id] != nil){
49 Response[id]!(response.actionIdentifier)
50 }
51 completionHandler()
52 }
53
54 }
55
1 import Foundation
2 //
3 // UNNofitication.swift
4 // ko-seigen
5 //
6 // Created by USER on 2017/10/04.
7 // Copyright © 2017年 ドラッサル 亜嵐. All rights reserved.
8 //
9
10 import Foundation
11 import UserNotifications
12
13 class UserNofitication:NSObject{
14 static let sharedInstance = UserNofitication()
15 @available(iOS 10.0, *)
16 public func easyNofitication(
17 identifier : String,
18 title : String,
19 body : String,
20 actions : [UNNotificationAction],
21 completionHandler :((Error?) -> Void)?,
22 response :UNResponseManager
23 ){
24
25
26 let category = UNNotificationCategory(identifier: identifier,
27 actions: actions ,
28 intentIdentifiers: [],
29 options: [])
30
31 UNUserNotificationCenter.current().setNotificationCategories([category])
32
33
34 let content = UNMutableNotificationContent()
35 content.title = title
36 content.body = body
37 content.sound = UNNotificationSound.default()
38 content.categoryIdentifier = identifier
39
40
41 let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
42 let request = UNNotificationRequest(identifier: identifier,
43 content: content,
44 trigger: trigger)
45 let center = UNUserNotificationCenter.current()
46 center.delegate = UNResponseManager.sharedInstance
47 center.add(request, withCompletionHandler:completionHandler)
48
49 }
50 }
51
1 //
2 // Use this file to import your target's public headers that you would like to expose to Swift.
3 //
4
1 //
2 // main.m
3 // jacket_ios
4 //
5 // Created by ドラッサル 亜嵐 on 2016/04/27.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10 #import "AppDelegate.h"
11
12 int main(int argc, char * argv[]) {
13 @autoreleasepool {
14 return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 }
16 }
1 //
2 // jacket_ios_prefix.pch
3 // tuber
4 //
5 // Created by ドラッサル 亜嵐 on 2016/06/09.
6 // Copyright © 2016年 ドラッサル 亜嵐. All rights reserved.
7 //
8
9 #ifndef jacket_ios_prefix_pch
10 #define jacket_ios_prefix_pch
11
12 // Include any system framework and library headers here that should be included in all compilation units.
13 // You will also need to set the Prefix Header build setting of one or more of your targets to reference this file.
14
15 #define URL_BASE @"http://jacketapi.momo-ltd.com"
16 #define URL_PATH_API @"/jacketapi/%@"
17
18 #define URL_PATH_STORE_FIRMWARE @"/jacketapi/firmware_download.php?uuid=%@"
19
20 #define USER_USERID @"username"
21 #define USER_PASSWORD @"password"
22
23 #define KEY_USER_USERID @"username"
24 #define KEY_USER_PASSWORD @"password"
25
26 #define AGENT_KEY @"agent"
27 #define VNAME_KEY @"vname"
28
29 #define DATABASE @"sqlitedb.sql"
30
31 #endif /* Tuber_Prefix_pch */