├── .gitignore ├── LICENSE ├── MobileGestalt.podspec ├── MobileGestalt └── Classes │ ├── Private │ ├── MGRequest+Private.h │ ├── MGTask.h │ └── MGTask.m │ └── Public │ ├── MGError.h │ ├── MGError.m │ ├── MGRequest.h │ ├── MGRequest.m │ ├── MGSession.h │ ├── MGSession.m │ ├── MGUtils.h │ ├── MGUtils.m │ └── MobileGestalt.h ├── MobileGestaltDemo ├── MobileGestaltDemo.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── MobileGestaltDemo.xcscheme ├── MobileGestaltDemo.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── MobileGestaltDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── Podfile ├── Podfile.lock ├── mdm.mobileconfig └── sign.mobileconfig └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Finder 6 | 7 | ## Build generated 8 | build/ 9 | DerivedData/ 10 | 11 | ## Various settings 12 | *.pbxuser 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | xcuserdata/ 21 | 22 | ## Other 23 | *.moved-aside 24 | *.xccheckout 25 | *.xcscmblueprint 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | # CocoaPods 34 | # 35 | # We recommend against adding the Pods directory to your .gitignore. However 36 | # you should judge for yourself, the pros and cons are mentioned at: 37 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 38 | # 39 | Pods/ 40 | 41 | # Carthage 42 | # 43 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 44 | # Carthage/Checkouts 45 | 46 | Carthage/Build 47 | 48 | # fastlane 49 | # 50 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 51 | # screenshots whenever they are needed. 52 | # For more information about the recommended setup visit: 53 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 54 | 55 | fastlane/report.xml 56 | fastlane/Preview.html 57 | fastlane/screenshots/**/*.png 58 | fastlane/test_output 59 | 60 | # Code Injection 61 | # 62 | # After new code Injection tools there's a generated folder /iOSInjectionProject 63 | # https://github.com/johnno1962/injectionforxcode 64 | 65 | iOSInjectionProject/ 66 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 冷秋 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MobileGestalt.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint MobileGestalt.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | # 13 | # These will help people to find your library, and whilst it 14 | # can feel like a chore to fill in it's definitely to your advantage. The 15 | # summary should be tweet-length, and the description more in depth. 16 | # 17 | 18 | s.name = "MobileGestalt" 19 | s.version = "0.2.0" 20 | s.summary = "Get iOS device UDID with public API" 21 | 22 | # This description is used to generate tags and improve search results. 23 | # * Think: What does it do? Why did you write it? What is the focus? 24 | # * Try to keep it short, snappy and to the point. 25 | # * Write the description between the DESC delimiters below. 26 | # * Finally, don't worry about the indent, CocoaPods strips it! 27 | s.description = <<-DESC 28 | - Use public APIs 29 | - Get iOS device information (UDID, IMEI, Product, Version) 30 | - Use signed profile 31 | DESC 32 | 33 | s.homepage = "https://github.com/Magic-Unique/MobileGestalt" 34 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" 35 | 36 | 37 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 38 | # 39 | # Licensing your code is important. See http://choosealicense.com for more info. 40 | # CocoaPods will detect a license file if there is a named LICENSE* 41 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. 42 | # 43 | 44 | s.license = "MIT" 45 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" } 46 | 47 | 48 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 49 | # 50 | # Specify the authors of the library, with email addresses. Email addresses 51 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also 52 | # accepts just a name if you'd rather not provide an email address. 53 | # 54 | # Specify a social_media_url where others can refer to, for example a twitter 55 | # profile URL. 56 | # 57 | 58 | s.author = { "冷秋" => "516563564@qq.com" } 59 | # Or just: s.author = "冷秋" 60 | # s.authors = { "冷秋" => "516563564@qq.com" } 61 | # s.social_media_url = "http://twitter.com/冷秋" 62 | 63 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 64 | # 65 | # If this Pod runs only on iOS or OS X, then specify the platform and 66 | # the deployment target. You can optionally include the target after the platform. 67 | # 68 | 69 | # s.platform = :ios 70 | s.platform = :ios, "8.0" 71 | 72 | # When using multiple platforms 73 | # s.ios.deployment_target = "5.0" 74 | # s.osx.deployment_target = "10.7" 75 | # s.watchos.deployment_target = "2.0" 76 | # s.tvos.deployment_target = "9.0" 77 | 78 | 79 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 80 | # 81 | # Specify the location from where the source should be retrieved. 82 | # Supports git, hg, bzr, svn and HTTP. 83 | # 84 | 85 | s.source = { :git => "https://github.com/Magic-Unique/MobileGestalt.git", :tag => "#{s.version}" } 86 | 87 | 88 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 89 | # 90 | # CocoaPods is smart about how it includes source code. For source files 91 | # giving a folder will include any swift, h, m, mm, c & cpp files. 92 | # For header files it will include any header in the folder. 93 | # Not including the public_header_files will make all headers public. 94 | # 95 | 96 | s.source_files = "MobileGestalt/Classes/**/*.{h,m}" #{}"Classes/**/*.{h,m}" 97 | # s.exclude_files = "Classes/Exclude" 98 | 99 | s.public_header_files = "MobileGestalt/Classes/Public/*.h" 100 | 101 | 102 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 103 | # 104 | # A list of resources included with the Pod. These are copied into the 105 | # target bundle with a build phase script. Anything else will be cleaned. 106 | # You can preserve files from being cleaned, please don't preserve 107 | # non-essential files like tests, examples and documentation. 108 | # 109 | 110 | # s.resource = "icon.png" 111 | # s.resources = "Resources/*.png" 112 | 113 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave" 114 | 115 | 116 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 117 | # 118 | # Link your library with frameworks, or libraries. Libraries do not include 119 | # the lib prefix of their name. 120 | # 121 | 122 | # s.framework = "SomeFramework" 123 | # s.frameworks = "SomeFramework", "AnotherFramework" 124 | 125 | # s.library = "iconv" 126 | # s.libraries = "iconv", "xml2" 127 | 128 | 129 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 130 | # 131 | # If your library depends on compiler flags you can set them in the xcconfig hash 132 | # where they will only apply to your library. If you depend on other Podspecs 133 | # you can include multiple dependencies to ensure it works. 134 | 135 | # s.requires_arc = true 136 | 137 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } 138 | s.dependency "GCDWebServer" 139 | 140 | end 141 | -------------------------------------------------------------------------------- /MobileGestalt/Classes/Private/MGRequest+Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGRequest+Private.h 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/10. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import "MGRequest.h" 10 | 11 | @interface MGCustomRequest : MGRequest 12 | 13 | @end 14 | 15 | @interface MGURLRequest : MGRequest 16 | 17 | @property (nonatomic, strong, readonly) NSURL *URL; 18 | 19 | @end 20 | 21 | @interface MGDataRequest : MGRequest 22 | 23 | @property (nonatomic, strong, readonly) NSData *data; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /MobileGestalt/Classes/Private/MGTask.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTask.h 3 | // MobileGestaltDemo 4 | // 5 | // Created by 吴双 on 2019/4/10. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MGUtils.h" 11 | 12 | @interface MGTask : NSObject 13 | 14 | @property (nonatomic, strong, readonly) MGRequest *request; 15 | @property (nonatomic, copy, readonly) MGCompletion completion; 16 | 17 | @property (nonatomic, strong, readonly) MGResponse *response; 18 | @property (nonatomic, strong, readonly) NSError *error; 19 | 20 | @property (nonatomic, assign) UIBackgroundTaskIdentifier bgTaskId; 21 | 22 | + (instancetype)taskWithRequest:(MGRequest *)request completion:(MGCompletion)completion; 23 | 24 | - (void)applicationWillEnterForeground; 25 | 26 | - (void)markError:(NSError *)error; 27 | - (void)markResponse:(MGResponse *)response; 28 | - (void)sendCompletion; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /MobileGestalt/Classes/Private/MGTask.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTask.m 3 | // MobileGestaltDemo 4 | // 5 | // Created by 吴双 on 2019/4/10. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import "MGTask.h" 10 | #import "MGError.h" 11 | #import 12 | #import 13 | 14 | @implementation MGTask 15 | 16 | + (instancetype)taskWithRequest:(MGRequest *)request completion:(MGCompletion)completion { 17 | MGTask *task = [[MGTask alloc] init]; 18 | task->_request = request; 19 | task->_completion = [completion copy]; 20 | return task; 21 | } 22 | 23 | - (void)applicationWillEnterForeground { 24 | if (!_response && !_error) { 25 | [self markError:MGCancelByUserError()]; 26 | } 27 | } 28 | 29 | - (void)markError:(NSError *)error { 30 | _error = error; 31 | _response = nil; 32 | } 33 | 34 | - (void)markResponse:(MGResponse *)response { 35 | _error = nil; 36 | _response = response; 37 | } 38 | 39 | - (void)sendCompletion { 40 | if (_completion) { 41 | if (_error || _response) { 42 | !_completion?:_completion(_request, _response, _error); 43 | } 44 | } 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /MobileGestalt/Classes/Public/MGError.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGError.h 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/8. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | FOUNDATION_EXTERN NSErrorDomain MGErrorDomain; 12 | 13 | typedef NS_ENUM(NSInteger, MGErrorCode) { 14 | MGErrorCodeSucceed, ///< Unused 15 | MGErrorCodeServerIsNotRunning, ///< GCDWebServer can not running before open *.mobileconfig. 16 | MGErrorCodeCannotBeginBackgroundTask, ///< MGSession can not begin a background task before open URL of *.mobileconfig 17 | MGErrorCodeCannotOpenMobileConfigURL, ///< Failed when UIApplication open URL of *.mobileconfig 18 | MGErrorCodeMobileConfigDataIsNil, ///< Can not respond *.mobileconfig request, because the data for response is nil. 19 | MGErrorCodeBackgroundTaskTimeout, ///< User does not install *.mobileconfig and make app in background so long. 20 | MGErrorCodeCancelByUser, ///< User reopen the app without installed *.mobileconfig 21 | }; 22 | 23 | FOUNDATION_EXTERN NSError *MGServerIsnotRunningError(void); 24 | FOUNDATION_EXTERN NSError *MGCannotBeginBackgroundTaskError(void); 25 | FOUNDATION_EXTERN NSError *MGCannotOpenMobileConfigURLError(void); 26 | FOUNDATION_EXTERN NSError *MGMobileConfigDataIsNilError(void); 27 | FOUNDATION_EXTERN NSError *MGBackgroundTaskTimeoutError(void); 28 | FOUNDATION_EXTERN NSError *MGCancelByUserError(void); 29 | -------------------------------------------------------------------------------- /MobileGestalt/Classes/Public/MGError.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGError.m 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/8. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import "MGError.h" 10 | 11 | NSErrorDomain MGErrorDomain = @"com.unique.mobilegestalt"; 12 | 13 | NSError *MGMakeError(MGErrorCode code, NSString *reason, NSString *suggestion) { 14 | return [NSError errorWithDomain:MGErrorDomain code:code userInfo:({ 15 | NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; 16 | userInfo[NSLocalizedDescriptionKey] = @"Cannot request mobile gestalt."; 17 | userInfo[NSLocalizedFailureReasonErrorKey] = reason; 18 | userInfo[NSLocalizedRecoverySuggestionErrorKey] = suggestion; 19 | [userInfo copy]; 20 | })]; 21 | } 22 | 23 | NSError *MGServerIsnotRunningError(void) { 24 | return MGMakeError(MGErrorCodeServerIsNotRunning, @"The server is not running", @"Change port and create a new session"); 25 | } 26 | 27 | NSError *MGCannotBeginBackgroundTaskError(void) { 28 | return MGMakeError(MGErrorCodeCannotBeginBackgroundTask, @"Can not begin background task.", @"Add background running mode to Info.plist file."); 29 | } 30 | 31 | NSError *MGCannotOpenMobileConfigURLError(void) { 32 | return MGMakeError(MGErrorCodeCannotOpenMobileConfigURL, @"Call -[UIApplication openURL:] failed.", @"Restart app or reboot device, then try again."); 33 | } 34 | 35 | NSError *MGMobileConfigDataIsNilError(void) { 36 | return MGMakeError(MGErrorCodeMobileConfigDataIsNil, @"MGRequest does not contains a data for *.mobileconfig response", @"Create a MGRequest with property or an URL or a local data"); 37 | } 38 | 39 | NSError *MGBackgroundTaskTimeoutError(void) { 40 | return MGMakeError(MGErrorCodeBackgroundTaskTimeout, @"Background task was expired.", @"Install file quickly."); 41 | } 42 | 43 | NSError *MGCancelByUserError(void) { 44 | return MGMakeError(MGErrorCodeCancelByUser, @"Cancel by user.", @"Install profile in Preferences."); 45 | } 46 | -------------------------------------------------------------------------------- /MobileGestalt/Classes/Public/MGRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGRequest.h 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/7. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MGUtils.h" 11 | 12 | @interface MGRequest : NSObject 13 | 14 | /** 15 | The device info key. 16 | */ 17 | @property (nonatomic, strong, nonnull) NSArray *attributes; 18 | 19 | /** 20 | Profile display name 21 | 22 | Default is CFBundleDisplayName 23 | */ 24 | @property (nonatomic, strong, nonnull) NSString *displayName; 25 | 26 | /** 27 | Profile organization 28 | 29 | Default is `Mobile Gestalt` 30 | */ 31 | @property (nonatomic, strong, nullable) NSString *organization; 32 | 33 | /** 34 | Profile description 35 | 36 | Default is `Install the profile to get your device info.` 37 | */ 38 | @property (nonatomic, strong, nullable) NSString *explain; 39 | 40 | /** 41 | Profile unique identifier 42 | 43 | Default is `{NSBundle.mainBundle.bundleIdentifier}.mobilegestalt` 44 | */ 45 | @property (nonatomic, strong, nonnull) NSString *identifier; 46 | 47 | /** 48 | Profile version 49 | 50 | Default is 1. 51 | */ 52 | @property (nonatomic, assign) NSInteger version; 53 | 54 | /** 55 | Profile UUID 56 | */ 57 | @property (nonatomic, strong, nonnull) NSUUID *UUID; 58 | 59 | 60 | /** 61 | Create custom request with default value 62 | 63 | @param title DisplayName 64 | @param subtitle Organization 65 | @param description Explain 66 | @return MGRequest 67 | */ 68 | + (instancetype _Nonnull)requestWithTitle:(NSString * _Nonnull)title subtitle:(NSString * _Nullable)subtitle description:(NSString * _Nullable)description; 69 | 70 | /** 71 | Create request with *.mobileconfig URL 72 | 73 | @param URL NSURL 74 | @return MGRequest 75 | */ 76 | + (instancetype _Nonnull)requestWithMobileConfigURL:(NSURL * _Nonnull)URL; 77 | 78 | /** 79 | Create request with *.mobileconfig data 80 | 81 | @param data NSData 82 | @return MGRequest 83 | */ 84 | + (instancetype _Nonnull)requestWithMobileConfigData:(NSData * _Nonnull)data; 85 | 86 | @end 87 | 88 | @interface MGResponse : NSObject 89 | 90 | /** 91 | Device info. 92 | */ 93 | @property (nonatomic, strong, readonly, nonnull) NSDictionary *data; 94 | 95 | @property (nonatomic, strong, readonly, nullable) NSString *UDID; 96 | @property (nonatomic, strong, readonly, nullable) NSString *IMEI; 97 | @property (nonatomic, strong, readonly, nullable) NSString *ICCID; ///< Maybe nil 98 | @property (nonatomic, strong, readonly, nullable) NSString *Version; 99 | @property (nonatomic, strong, readonly, nullable) NSString *Product; 100 | 101 | + (instancetype _Nonnull)responseWithData:(NSData * _Nonnull)data; 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /MobileGestalt/Classes/Public/MGRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGRequest.m 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/7. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import "MGRequest.h" 10 | #import "MGRequest+Private.h" 11 | 12 | @implementation MGRequest 13 | 14 | + (instancetype)requestWithTitle:(NSString *)title subtitle:(NSString *)subtitle description:(NSString *)description { 15 | return [MGCustomRequest requestWithTitle:title subtitle:subtitle description:description]; 16 | } 17 | 18 | + (instancetype)requestWithMobileConfigURL:(NSURL *)URL { 19 | NSParameterAssert(URL); 20 | return [MGURLRequest requestWithMobileConfigURL:URL]; 21 | } 22 | 23 | + (instancetype)requestWithMobileConfigData:(NSData *)data { 24 | NSParameterAssert(data); 25 | return [MGDataRequest requestWithMobileConfigData:data]; 26 | } 27 | 28 | @end 29 | 30 | @implementation MGCustomRequest 31 | 32 | + (instancetype)requestWithTitle:(NSString *)title subtitle:(NSString *)subtitle description:(NSString *)description { 33 | MGCustomRequest *request = [[self alloc] init]; 34 | request.displayName = title; 35 | request.organization = subtitle; 36 | request.explain = description; 37 | return request; 38 | } 39 | 40 | - (instancetype)init { 41 | self = [super init]; 42 | if (self) { 43 | self.attributes = @[MGAttributeUDID, 44 | MGAttributeIMEI, 45 | MGAttributeICCID, 46 | MGAttributeVersion, 47 | MGAttributeProduct]; 48 | self.organization = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];; 49 | self.displayName = @"Mobile Gestalt"; 50 | self.UUID = [NSUUID UUID]; 51 | self.identifier = [[[NSBundle mainBundle] bundleIdentifier] stringByAppendingString:@".mobilegestalt"]; 52 | self.explain = @"Install the profile to get your device info."; 53 | self.version = 1; 54 | } 55 | return self; 56 | } 57 | 58 | @end 59 | 60 | @implementation MGURLRequest 61 | 62 | + (instancetype)requestWithMobileConfigURL:(NSURL *)URL { 63 | NSParameterAssert(URL); 64 | return [[self alloc] initWithMobileConfigURL:URL]; 65 | } 66 | 67 | - (instancetype)initWithMobileConfigURL:(NSURL *)URL { 68 | self = [super init]; 69 | if (self) { 70 | _URL = URL; 71 | } 72 | return self; 73 | } 74 | 75 | @end 76 | 77 | @implementation MGDataRequest 78 | 79 | + (instancetype)requestWithMobileConfigData:(NSData *)data { 80 | NSParameterAssert(data); 81 | return [[self alloc] initWithMobileConfigData:data]; 82 | } 83 | 84 | - (instancetype)initWithMobileConfigData:(NSData *)data { 85 | self = [super init]; 86 | if (self) { 87 | _data = data; 88 | } 89 | return self; 90 | } 91 | 92 | @end 93 | 94 | @implementation MGResponse 95 | 96 | + (instancetype)responseWithData:(NSData *)data { 97 | NSRange rangeBegin = [data rangeOfData:[@"" dataUsingEncoding:NSASCIIStringEncoding] options:0 range:NSMakeRange(0, data.length)]; 99 | NSData *plistData = [data subdataWithRange:NSMakeRange(rangeBegin.location, rangeEnd.location + rangeEnd.location - rangeBegin.location)]; 100 | NSDictionary *plistDict = [NSPropertyListSerialization propertyListWithData:plistData options:0 format:NULL error:NULL]; 101 | MGResponse *response = [[self alloc] init]; 102 | response->_data = plistDict; 103 | return response; 104 | } 105 | 106 | - (NSString *)UDID { 107 | return self.data[MGAttributeUDID]; 108 | } 109 | 110 | - (NSString *)IMEI { 111 | return self.data[MGAttributeIMEI]; 112 | } 113 | 114 | - (NSString *)ICCID { 115 | return self.data[MGAttributeICCID]; 116 | } 117 | 118 | - (NSString *)Version { 119 | return self.data[MGAttributeVersion]; 120 | } 121 | 122 | - (NSString *)Product { 123 | return self.data[MGAttributeProduct]; 124 | } 125 | 126 | @end 127 | -------------------------------------------------------------------------------- /MobileGestalt/Classes/Public/MGSession.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGSession.h 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/7. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MGUtils.h" 11 | 12 | @class MGRequest, MGResponse; 13 | 14 | @interface MGSessionConfiguration : NSObject 15 | 16 | /** 17 | Local server port, default is 10418. Set 0 to use random port. 18 | */ 19 | @property (nonatomic, assign) NSUInteger port; 20 | 21 | /** 22 | Local server port offset. Default is 0 (not offset) 23 | 24 | If port is not usable, MGSession will use offset-port. Range is [port, port + portOffset] 25 | */ 26 | @property (nonatomic, assign) NSUInteger portOffset; 27 | 28 | /** 29 | Local server *.mobileconfig path. Default: /MobileGestalt/mdm.mobileconfig 30 | */ 31 | @property (nonatomic, copy, nonnull) NSString *mobileConfigPath; 32 | 33 | /** 34 | Local server register path, Default: /MobileGestalt/register 35 | 36 | Register path must writen in *.mobileconfig file with key `PayloadContent.URL`. 37 | For MGCustomRequest: it will pass to request. 38 | For MGNormalRequest, you must use a *.mobileconfig with this registerPath, 39 | */ 40 | @property (nonatomic, copy, nonnull) NSString *registerPath; 41 | 42 | /** 43 | Callback URL scheme. 44 | 45 | Add an URLScheme to Info.plist, and pass it here. It will auto jump back after user install profile. 46 | */ 47 | @property (nonatomic, strong, nullable) NSString *callbackScheme; 48 | 49 | @property (nonatomic, assign) BOOL log; 50 | 51 | /** 52 | Configuration with default value 53 | 54 | @return MGSessionConfiguration 55 | */ 56 | + (instancetype _Nonnull)defaultConfiguration; 57 | 58 | @end 59 | 60 | @interface MGSession : NSObject 61 | 62 | /** 63 | Configuration 64 | */ 65 | @property (nonatomic, strong, readonly, nonnull) MGSessionConfiguration *configuration; 66 | 67 | /** 68 | Enable 69 | 70 | If the server was failed in starting, enable will be NO, any request can not work. 71 | */ 72 | @property (nonatomic, assign, readonly) BOOL enable; 73 | 74 | /** 75 | Error 76 | 77 | Server error for starting. 78 | */ 79 | @property (nonatomic, strong, readonly, nullable) NSError *error; 80 | 81 | /** 82 | Server port. Return 0 if the server did not start. 83 | */ 84 | @property (nonatomic, assign, readonly) NSUInteger port; 85 | 86 | /** 87 | Create session with configuration 88 | 89 | @param configuration MGSessionConfiguration 90 | @return MGSession 91 | */ 92 | + (instancetype _Nonnull)sessionWithConfiguration:(MGSessionConfiguration * _Nonnull)configuration; 93 | 94 | /** 95 | Create session with default configuration 96 | 97 | @return MGSession 98 | */ 99 | + (instancetype _Nonnull)defaultSession; 100 | 101 | /** 102 | Send request 103 | 104 | @param request MGRequest 105 | @param completed Completion 106 | */ 107 | - (void)request:(MGRequest * _Nonnull)request completed:(MGCompletion _Nullable)completed; 108 | 109 | @end 110 | -------------------------------------------------------------------------------- /MobileGestalt/Classes/Public/MGSession.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGSession.m 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/7. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import "MGSession.h" 10 | #import 11 | #import 12 | #import 13 | #import 14 | 15 | #import "MGRequest.h" 16 | #import "MGRequest+Private.h" 17 | #import "MGTask.h" 18 | #import "MGError.h" 19 | 20 | #define MGWeak(obj) __weak typeof(obj) weak_##obj = obj 21 | #define MGStrong(obj) __strong typeof(weak_##obj) obj = weak_##obj; 22 | 23 | #define MGLog(...) do { if (self.configuration.log) { NSLog(@"MobileGestalt: %@", [NSString stringWithFormat:__VA_ARGS__]); }} while(0); 24 | 25 | void MGRunInMain(void (^block)(void)) { 26 | if ([NSThread isMainThread]) { 27 | block(); 28 | } else { 29 | dispatch_async(dispatch_get_main_queue(), block); 30 | } 31 | } 32 | 33 | void MGOpenURL(NSURL *URL, void (^completed)(BOOL success)) { 34 | if (@available(iOS 10.0, *)) { 35 | [[UIApplication sharedApplication] openURL:URL options:@{} completionHandler:completed]; 36 | } else { 37 | BOOL success = NO; 38 | #pragma clang diagnostic push 39 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 40 | success = [[UIApplication sharedApplication] openURL:URL]; 41 | #pragma clang diagnostic pop 42 | !completed?:completed(success); 43 | } 44 | } 45 | 46 | @interface MGSession () 47 | 48 | @property (nonatomic, strong, readonly) GCDWebServer *server; 49 | 50 | @property (nonatomic, strong, readonly) MGTask *task; 51 | @property (nonatomic, assign, readonly) UIBackgroundTaskIdentifier bgTaskId; 52 | 53 | @end 54 | 55 | @implementation MGSession 56 | 57 | + (instancetype)sessionWithConfiguration:(MGSessionConfiguration *)configuration { 58 | NSParameterAssert(configuration); 59 | return [[self alloc] initWithConfiguration:configuration]; 60 | } 61 | 62 | + (instancetype)defaultSession { 63 | return [self sessionWithConfiguration:[MGSessionConfiguration defaultConfiguration]]; 64 | } 65 | 66 | - (instancetype)initWithConfiguration:(MGSessionConfiguration *)configuration { 67 | self = [super init]; 68 | if (self) { 69 | _configuration = configuration; 70 | _server = [[GCDWebServer alloc] init]; 71 | [self __initHandler]; 72 | 73 | NSError *error = nil; 74 | BOOL result = NO; 75 | NSUInteger port = configuration.port; 76 | do { 77 | result = [self.server startWithOptions:@{GCDWebServerOption_Port:@(port), 78 | GCDWebServerOption_BindToLocalhost:@YES, 79 | GCDWebServerOption_AutomaticallySuspendInBackground:@NO} error:&error]; 80 | if (result) { 81 | MGLog(@"Server is running in port %@", @(self.server.port)); 82 | break; 83 | } else { 84 | MGLog(@"Server can not running in port %@", @(port)); 85 | } 86 | port++; 87 | } while (port < configuration.port + configuration.portOffset); 88 | _enable = result; 89 | if (!result) { 90 | _error = error; 91 | MGLog(@"Server can not running"); 92 | } else { 93 | [self installUIApplicationDelegate:YES]; 94 | } 95 | } 96 | return self; 97 | } 98 | 99 | - (void)dealloc { 100 | if (self.server.isRunning) { 101 | [self.server stop]; 102 | } 103 | [self installUIApplicationDelegate:NO]; 104 | } 105 | 106 | - (void)installUIApplicationDelegate:(BOOL)install { 107 | if (install) { 108 | [[NSNotificationCenter defaultCenter] addObserver:self 109 | selector:@selector(applicationDidEnterBackground:) 110 | name:UIApplicationDidEnterBackgroundNotification 111 | object:nil]; 112 | [[NSNotificationCenter defaultCenter] addObserver:self 113 | selector:@selector(applicationWillEnterForeground:) 114 | name:UIApplicationWillEnterForegroundNotification 115 | object:nil]; 116 | } else { 117 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 118 | } 119 | } 120 | 121 | - (void)applicationDidEnterBackground:(NSNotification *)notification { 122 | } 123 | 124 | - (void)applicationWillEnterForeground:(NSNotification *)notification { 125 | [self.task applicationWillEnterForeground]; 126 | [self __completion]; 127 | 128 | if (self.bgTaskId != UIBackgroundTaskInvalid) { 129 | [[UIApplication sharedApplication] endBackgroundTask:self.bgTaskId]; 130 | self->_bgTaskId = UIBackgroundTaskInvalid; 131 | } 132 | } 133 | 134 | - (void)request:(MGRequest *)request completed:(MGCompletion)completed { 135 | if (![request isKindOfClass:[MGRequest class]] && [request isMemberOfClass:[MGRequest class]]) { 136 | NSAssert(NO, @"Request must subclass of MGRequest, use +[MGRequest requestWith...] to create instance."); 137 | } 138 | _task = [MGTask taskWithRequest:request completion:completed]; 139 | 140 | MGWeak(self); 141 | MGRunInMain(^{ 142 | MGStrong(self); 143 | 144 | if (!self.server.isRunning) { 145 | [self __markError:MGServerIsnotRunningError()]; 146 | [self __completion]; 147 | return ; 148 | } 149 | 150 | // Begin background task 151 | self->_bgTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"com.unique.MobileGestalt" expirationHandler:^{ 152 | MGStrong(self); 153 | self->_bgTaskId = UIBackgroundTaskInvalid; 154 | [self __markError:MGBackgroundTaskTimeoutError()]; 155 | [self __completion]; 156 | }]; 157 | if (self.bgTaskId == UIBackgroundTaskInvalid) { 158 | [self __markError:MGCannotBeginBackgroundTaskError()]; 159 | [self __completion]; 160 | return ; 161 | } 162 | 163 | MGOpenURL([NSURL URLWithString:[self __mobileConfigURL]], ^(BOOL success) { 164 | if (!success) { 165 | MGStrong(self) 166 | [self __markError:MGCannotOpenMobileConfigURLError()]; 167 | [self __completion]; 168 | } 169 | }); 170 | }); 171 | } 172 | 173 | - (void)__initHandler { 174 | MGWeak(self); 175 | [_server addHandlerForMethod:@"GET" 176 | path:self.configuration.mobileConfigPath 177 | requestClass:[GCDWebServerDataRequest class] 178 | processBlock:^GCDWebServerResponse *(GCDWebServerDataRequest* request) { 179 | MGStrong(self); 180 | if (!self.task) { 181 | MGLog(@"Current task is nil, respond with 404"); 182 | return [GCDWebServerResponse responseWithStatusCode:404]; 183 | } 184 | 185 | if ([self.task.request isKindOfClass:[MGURLRequest class]]) { 186 | MGURLRequest *_request = (MGURLRequest *)self.task.request; 187 | if (_request.URL) { 188 | return [GCDWebServerResponse responseWithRedirect:_request.URL permanent:YES]; 189 | } 190 | } 191 | 192 | NSData *data = nil; 193 | if ([self.task.request isKindOfClass:[MGCustomRequest class]]) { 194 | MGCustomRequest *_request = (MGCustomRequest *)self.task.request; 195 | data = [self __mobileConfigDataWithRequest:_request]; 196 | } else if ([self.task.request isKindOfClass:[MGDataRequest class]]) { 197 | MGDataRequest *_request = (MGDataRequest *)self.task.request; 198 | if (_request.data) { 199 | data = _request.data; 200 | } 201 | } 202 | if (!data) { 203 | [self __markError:MGMobileConfigDataIsNilError()]; 204 | return [GCDWebServerDataResponse responseWithStatusCode:404]; 205 | } 206 | return [[GCDWebServerDataResponse alloc] initWithData:data contentType:@"application/x-apple-aspen-config"]; 207 | }]; 208 | [_server addHandlerForMethod:@"POST" 209 | path:self.configuration.registerPath 210 | requestClass:[GCDWebServerDataRequest class] 211 | processBlock:^GCDWebServerResponse *(GCDWebServerDataRequest *request) { 212 | MGStrong(self); 213 | if (!self.task) { 214 | MGLog(@"Current task is nil, respond with 404"); 215 | return [GCDWebServerResponse responseWithStatusCode:404]; 216 | } 217 | 218 | MGResponse *response = [MGResponse responseWithData:request.data]; 219 | [self __markResponse:response]; 220 | 221 | NSString *URL = nil; 222 | if (self.configuration.callbackScheme) { 223 | NSString *scheme = self.configuration.callbackScheme; 224 | NSMutableArray *datas = [NSMutableArray array]; 225 | [response.data enumerateKeysAndObjectsUsingBlock:^(MGAttribute key, NSString *obj, BOOL *stop) { 226 | [datas addObject:[NSString stringWithFormat:@"%@=%@", key, obj]]; 227 | }]; 228 | NSString *parames = [datas componentsJoinedByString:@"&"]; 229 | URL = [NSString stringWithFormat:@"%@://mobilegestalt?%@", scheme, parames]; 230 | URL = [URL stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]; 231 | } else { 232 | URL = UIApplicationOpenSettingsURLString; 233 | } 234 | 235 | return [[GCDWebServerResponse alloc] initWithRedirect:[NSURL URLWithString:URL] permanent:YES]; 236 | }]; 237 | } 238 | 239 | - (void)__markError:(NSError *)error { 240 | MGLog(@"Receive error %@", error); 241 | [self.task markError:error]; 242 | } 243 | 244 | - (void)__markResponse:(MGResponse *)response { 245 | MGLog(@"Receive informations %@", response.data); 246 | [self.task markResponse:response]; 247 | } 248 | 249 | - (void)__completion { 250 | [self.task sendCompletion]; 251 | _task = nil; 252 | } 253 | 254 | - (NSData *)__mobileConfigDataWithRequest:(MGCustomRequest *)request { 255 | NSMutableDictionary *mobileConfig = [NSMutableDictionary dictionary]; 256 | mobileConfig[@"PayloadOrganization"] = request.organization; 257 | mobileConfig[@"PayloadDisplayName"] = request.displayName; 258 | mobileConfig[@"PayloadVersion"] = @(request.version); 259 | mobileConfig[@"PayloadUUID"] = request.UUID.UUIDString; 260 | mobileConfig[@"PayloadIdentifier"] = request.identifier; 261 | mobileConfig[@"PayloadDescription"] = request.explain; 262 | mobileConfig[@"PayloadType"] = @"Profile Service"; 263 | mobileConfig[@"PayloadContent"] = @{@"URL": [self __registerURL], @"DeviceAttributes": request.attributes}; 264 | NSData *data = [NSPropertyListSerialization dataWithPropertyList:mobileConfig format:NSPropertyListXMLFormat_v1_0 options:0 error:NULL]; 265 | return data; 266 | } 267 | 268 | - (NSString *)__mobileConfigURL { 269 | NSString *URL = [NSString stringWithFormat:@"http://127.0.0.1:%@%@", @(self.server.port), self.configuration.mobileConfigPath]; 270 | return URL; 271 | } 272 | 273 | - (NSString *)__registerURL { 274 | NSString *URL = [NSString stringWithFormat:@"http://127.0.0.1:%@%@", @(self.server.port), self.configuration.registerPath]; 275 | return URL; 276 | } 277 | 278 | - (NSUInteger)port { 279 | if (self.enable) { 280 | return self.server.port; 281 | } else { 282 | return 0; 283 | } 284 | } 285 | 286 | @end 287 | 288 | @implementation MGSessionConfiguration 289 | 290 | + (instancetype)defaultConfiguration { 291 | MGSessionConfiguration *configuration = [[MGSessionConfiguration alloc] init]; 292 | #if DEBUG == 1 293 | configuration.log = YES; 294 | #endif 295 | return configuration; 296 | } 297 | 298 | - (instancetype)init { 299 | self = [super init]; 300 | if (self) { 301 | self.port = 10418; 302 | self.portOffset = 0; 303 | self.mobileConfigPath = @"/MobileGestalt/mdm.mobileconfig"; 304 | self.registerPath = @"/MobileGestalt/register"; 305 | self.callbackScheme = @"mobilegestalt"; 306 | } 307 | return self; 308 | } 309 | 310 | @end 311 | -------------------------------------------------------------------------------- /MobileGestalt/Classes/Public/MGUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGUtils.h 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/8. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class MGRequest, MGResponse, NSError; 12 | 13 | typedef NSString *MGAttribute; 14 | 15 | FOUNDATION_EXTERN MGAttribute _Nonnull MGAttributeUDID; 16 | FOUNDATION_EXTERN MGAttribute _Nonnull MGAttributeIMEI; 17 | FOUNDATION_EXTERN MGAttribute _Nonnull MGAttributeICCID; 18 | FOUNDATION_EXTERN MGAttribute _Nonnull MGAttributeVersion; 19 | FOUNDATION_EXTERN MGAttribute _Nonnull MGAttributeProduct; 20 | 21 | typedef void(^MGCompletion)(MGRequest * _Nonnull request, MGResponse * _Nullable response, NSError * _Nullable error); 22 | -------------------------------------------------------------------------------- /MobileGestalt/Classes/Public/MGUtils.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGUtils.m 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/8. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import "MGUtils.h" 10 | 11 | MGAttribute MGAttributeUDID = @"UDID"; 12 | MGAttribute MGAttributeIMEI = @"IMEI"; 13 | MGAttribute MGAttributeICCID = @"ICCID"; 14 | MGAttribute MGAttributeVersion = @"VERSION"; 15 | MGAttribute MGAttributeProduct = @"PRODUCT"; 16 | -------------------------------------------------------------------------------- /MobileGestalt/Classes/Public/MobileGestalt.h: -------------------------------------------------------------------------------- 1 | // 2 | // MobileGestalt.h 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/8. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #ifndef MobileGestalt_h 10 | #define MobileGestalt_h 11 | 12 | #import "MGSession.h" 13 | #import "MGRequest.h" 14 | #import "MGUtils.h" 15 | #import "MGError.h" 16 | 17 | #endif /* MobileGestalt_h */ 18 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 165CC0920590671A3475E487 /* libPods-MobileGestaltDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AC92B0887D7823F66262BC5 /* libPods-MobileGestaltDemo.a */; }; 11 | 7E30D708225C4B4A00D0BE43 /* sign.mobileconfig in Resources */ = {isa = PBXBuildFile; fileRef = 7E30D707225C4B4A00D0BE43 /* sign.mobileconfig */; }; 12 | 7E3B7B1D225A48C100261F51 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E3B7B1C225A48C100261F51 /* AppDelegate.m */; }; 13 | 7E3B7B20225A48C100261F51 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E3B7B1F225A48C100261F51 /* ViewController.m */; }; 14 | 7E3B7B23225A48C100261F51 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7E3B7B21225A48C100261F51 /* Main.storyboard */; }; 15 | 7E3B7B25225A48C300261F51 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7E3B7B24225A48C300261F51 /* Assets.xcassets */; }; 16 | 7E3B7B28225A48C300261F51 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7E3B7B26225A48C300261F51 /* LaunchScreen.storyboard */; }; 17 | 7E3B7B2B225A48C300261F51 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E3B7B2A225A48C300261F51 /* main.m */; }; 18 | 7EA83BF1225D8CC600A595D7 /* MGError.m in Sources */ = {isa = PBXBuildFile; fileRef = 7EA83BE6225D8CC600A595D7 /* MGError.m */; }; 19 | 7EA83BF2225D8CC600A595D7 /* MGUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 7EA83BE7225D8CC600A595D7 /* MGUtils.m */; }; 20 | 7EA83BF3225D8CC600A595D7 /* MGSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 7EA83BE9225D8CC600A595D7 /* MGSession.m */; }; 21 | 7EA83BF4225D8CC600A595D7 /* MGRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7EA83BEA225D8CC600A595D7 /* MGRequest.m */; }; 22 | 7EA83BF7225D8CE600A595D7 /* MGTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 7EA83BF6225D8CE600A595D7 /* MGTask.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 7481E0DBC8054AF227AA4518 /* Pods-MobileGestaltDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MobileGestaltDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MobileGestaltDemo/Pods-MobileGestaltDemo.debug.xcconfig"; sourceTree = ""; }; 27 | 7A2249673B1C4E8A792C1987 /* Pods-MobileGestaltDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MobileGestaltDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-MobileGestaltDemo/Pods-MobileGestaltDemo.release.xcconfig"; sourceTree = ""; }; 28 | 7E30D707225C4B4A00D0BE43 /* sign.mobileconfig */ = {isa = PBXFileReference; lastKnownFileType = file; path = sign.mobileconfig; sourceTree = SOURCE_ROOT; }; 29 | 7E3B7B18225A48C100261F51 /* MobileGestaltDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MobileGestaltDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | 7E3B7B1B225A48C100261F51 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 31 | 7E3B7B1C225A48C100261F51 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 32 | 7E3B7B1E225A48C100261F51 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 33 | 7E3B7B1F225A48C100261F51 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 34 | 7E3B7B22225A48C100261F51 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 35 | 7E3B7B24225A48C300261F51 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 36 | 7E3B7B27225A48C300261F51 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 37 | 7E3B7B29225A48C300261F51 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 38 | 7E3B7B2A225A48C300261F51 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 39 | 7EA83BE6225D8CC600A595D7 /* MGError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGError.m; sourceTree = ""; }; 40 | 7EA83BE7225D8CC600A595D7 /* MGUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGUtils.m; sourceTree = ""; }; 41 | 7EA83BE8225D8CC600A595D7 /* MobileGestalt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobileGestalt.h; sourceTree = ""; }; 42 | 7EA83BE9225D8CC600A595D7 /* MGSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGSession.m; sourceTree = ""; }; 43 | 7EA83BEA225D8CC600A595D7 /* MGRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGRequest.m; sourceTree = ""; }; 44 | 7EA83BEB225D8CC600A595D7 /* MGUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGUtils.h; sourceTree = ""; }; 45 | 7EA83BEC225D8CC600A595D7 /* MGError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGError.h; sourceTree = ""; }; 46 | 7EA83BED225D8CC600A595D7 /* MGSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGSession.h; sourceTree = ""; }; 47 | 7EA83BEE225D8CC600A595D7 /* MGRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGRequest.h; sourceTree = ""; }; 48 | 7EA83BF0225D8CC600A595D7 /* MGRequest+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGRequest+Private.h"; sourceTree = ""; }; 49 | 7EA83BF5225D8CE600A595D7 /* MGTask.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGTask.h; sourceTree = ""; }; 50 | 7EA83BF6225D8CE600A595D7 /* MGTask.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGTask.m; sourceTree = ""; }; 51 | 9AC92B0887D7823F66262BC5 /* libPods-MobileGestaltDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MobileGestaltDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | 7E3B7B15225A48C100261F51 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | 165CC0920590671A3475E487 /* libPods-MobileGestaltDemo.a in Frameworks */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXFrameworksBuildPhase section */ 64 | 65 | /* Begin PBXGroup section */ 66 | 23C846E50204982205300097 /* Frameworks */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | 9AC92B0887D7823F66262BC5 /* libPods-MobileGestaltDemo.a */, 70 | ); 71 | name = Frameworks; 72 | sourceTree = ""; 73 | }; 74 | 7E3B7B0F225A48C100261F51 = { 75 | isa = PBXGroup; 76 | children = ( 77 | 7E3B7B1A225A48C100261F51 /* MobileGestaltDemo */, 78 | 7E3B7B19225A48C100261F51 /* Products */, 79 | C7B8276E55A1E6DFA2E81BBE /* Pods */, 80 | 23C846E50204982205300097 /* Frameworks */, 81 | ); 82 | sourceTree = ""; 83 | }; 84 | 7E3B7B19225A48C100261F51 /* Products */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 7E3B7B18225A48C100261F51 /* MobileGestaltDemo.app */, 88 | ); 89 | name = Products; 90 | sourceTree = ""; 91 | }; 92 | 7E3B7B1A225A48C100261F51 /* MobileGestaltDemo */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 7EA83BE3225D8CC600A595D7 /* MobileGestalt */, 96 | 7E3B7B1B225A48C100261F51 /* AppDelegate.h */, 97 | 7E3B7B1C225A48C100261F51 /* AppDelegate.m */, 98 | 7E3B7B1E225A48C100261F51 /* ViewController.h */, 99 | 7E3B7B1F225A48C100261F51 /* ViewController.m */, 100 | 7E30D707225C4B4A00D0BE43 /* sign.mobileconfig */, 101 | 7E3B7B21225A48C100261F51 /* Main.storyboard */, 102 | 7E3B7B24225A48C300261F51 /* Assets.xcassets */, 103 | 7E3B7B26225A48C300261F51 /* LaunchScreen.storyboard */, 104 | 7E3B7B29225A48C300261F51 /* Info.plist */, 105 | 7E3B7B2A225A48C300261F51 /* main.m */, 106 | ); 107 | path = MobileGestaltDemo; 108 | sourceTree = ""; 109 | }; 110 | 7EA83BE3225D8CC600A595D7 /* MobileGestalt */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 7EA83BE4225D8CC600A595D7 /* Classes */, 114 | ); 115 | name = MobileGestalt; 116 | path = ../../MobileGestalt; 117 | sourceTree = ""; 118 | }; 119 | 7EA83BE4225D8CC600A595D7 /* Classes */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 7EA83BE5225D8CC600A595D7 /* Public */, 123 | 7EA83BEF225D8CC600A595D7 /* Private */, 124 | ); 125 | path = Classes; 126 | sourceTree = ""; 127 | }; 128 | 7EA83BE5225D8CC600A595D7 /* Public */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 7EA83BEC225D8CC600A595D7 /* MGError.h */, 132 | 7EA83BE6225D8CC600A595D7 /* MGError.m */, 133 | 7EA83BEE225D8CC600A595D7 /* MGRequest.h */, 134 | 7EA83BEA225D8CC600A595D7 /* MGRequest.m */, 135 | 7EA83BED225D8CC600A595D7 /* MGSession.h */, 136 | 7EA83BE9225D8CC600A595D7 /* MGSession.m */, 137 | 7EA83BEB225D8CC600A595D7 /* MGUtils.h */, 138 | 7EA83BE7225D8CC600A595D7 /* MGUtils.m */, 139 | 7EA83BE8225D8CC600A595D7 /* MobileGestalt.h */, 140 | ); 141 | path = Public; 142 | sourceTree = ""; 143 | }; 144 | 7EA83BEF225D8CC600A595D7 /* Private */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 7EA83BF0225D8CC600A595D7 /* MGRequest+Private.h */, 148 | 7EA83BF5225D8CE600A595D7 /* MGTask.h */, 149 | 7EA83BF6225D8CE600A595D7 /* MGTask.m */, 150 | ); 151 | path = Private; 152 | sourceTree = ""; 153 | }; 154 | C7B8276E55A1E6DFA2E81BBE /* Pods */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | 7481E0DBC8054AF227AA4518 /* Pods-MobileGestaltDemo.debug.xcconfig */, 158 | 7A2249673B1C4E8A792C1987 /* Pods-MobileGestaltDemo.release.xcconfig */, 159 | ); 160 | name = Pods; 161 | sourceTree = ""; 162 | }; 163 | /* End PBXGroup section */ 164 | 165 | /* Begin PBXNativeTarget section */ 166 | 7E3B7B17225A48C100261F51 /* MobileGestaltDemo */ = { 167 | isa = PBXNativeTarget; 168 | buildConfigurationList = 7E3B7B2E225A48C300261F51 /* Build configuration list for PBXNativeTarget "MobileGestaltDemo" */; 169 | buildPhases = ( 170 | A2715984A9C7DDD498A34E14 /* [CP] Check Pods Manifest.lock */, 171 | 7E3B7B14225A48C100261F51 /* Sources */, 172 | 7E3B7B15225A48C100261F51 /* Frameworks */, 173 | 7E3B7B16225A48C100261F51 /* Resources */, 174 | ); 175 | buildRules = ( 176 | ); 177 | dependencies = ( 178 | ); 179 | name = MobileGestaltDemo; 180 | productName = MobileGestaltDemo; 181 | productReference = 7E3B7B18225A48C100261F51 /* MobileGestaltDemo.app */; 182 | productType = "com.apple.product-type.application"; 183 | }; 184 | /* End PBXNativeTarget section */ 185 | 186 | /* Begin PBXProject section */ 187 | 7E3B7B10225A48C100261F51 /* Project object */ = { 188 | isa = PBXProject; 189 | attributes = { 190 | CLASSPREFIX = MG; 191 | LastUpgradeCheck = 1020; 192 | ORGANIZATIONNAME = "Magic-Unique"; 193 | TargetAttributes = { 194 | 7E3B7B17225A48C100261F51 = { 195 | CreatedOnToolsVersion = 10.2; 196 | SystemCapabilities = { 197 | com.apple.BackgroundModes = { 198 | enabled = 0; 199 | }; 200 | }; 201 | }; 202 | }; 203 | }; 204 | buildConfigurationList = 7E3B7B13225A48C100261F51 /* Build configuration list for PBXProject "MobileGestaltDemo" */; 205 | compatibilityVersion = "Xcode 9.3"; 206 | developmentRegion = en; 207 | hasScannedForEncodings = 0; 208 | knownRegions = ( 209 | en, 210 | Base, 211 | ); 212 | mainGroup = 7E3B7B0F225A48C100261F51; 213 | productRefGroup = 7E3B7B19225A48C100261F51 /* Products */; 214 | projectDirPath = ""; 215 | projectRoot = ""; 216 | targets = ( 217 | 7E3B7B17225A48C100261F51 /* MobileGestaltDemo */, 218 | ); 219 | }; 220 | /* End PBXProject section */ 221 | 222 | /* Begin PBXResourcesBuildPhase section */ 223 | 7E3B7B16225A48C100261F51 /* Resources */ = { 224 | isa = PBXResourcesBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | 7E3B7B28225A48C300261F51 /* LaunchScreen.storyboard in Resources */, 228 | 7E3B7B25225A48C300261F51 /* Assets.xcassets in Resources */, 229 | 7E30D708225C4B4A00D0BE43 /* sign.mobileconfig in Resources */, 230 | 7E3B7B23225A48C100261F51 /* Main.storyboard in Resources */, 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | }; 234 | /* End PBXResourcesBuildPhase section */ 235 | 236 | /* Begin PBXShellScriptBuildPhase section */ 237 | A2715984A9C7DDD498A34E14 /* [CP] Check Pods Manifest.lock */ = { 238 | isa = PBXShellScriptBuildPhase; 239 | buildActionMask = 2147483647; 240 | files = ( 241 | ); 242 | inputFileListPaths = ( 243 | ); 244 | inputPaths = ( 245 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 246 | "${PODS_ROOT}/Manifest.lock", 247 | ); 248 | name = "[CP] Check Pods Manifest.lock"; 249 | outputFileListPaths = ( 250 | ); 251 | outputPaths = ( 252 | "$(DERIVED_FILE_DIR)/Pods-MobileGestaltDemo-checkManifestLockResult.txt", 253 | ); 254 | runOnlyForDeploymentPostprocessing = 0; 255 | shellPath = /bin/sh; 256 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 257 | showEnvVarsInLog = 0; 258 | }; 259 | /* End PBXShellScriptBuildPhase section */ 260 | 261 | /* Begin PBXSourcesBuildPhase section */ 262 | 7E3B7B14225A48C100261F51 /* Sources */ = { 263 | isa = PBXSourcesBuildPhase; 264 | buildActionMask = 2147483647; 265 | files = ( 266 | 7EA83BF3225D8CC600A595D7 /* MGSession.m in Sources */, 267 | 7EA83BF2225D8CC600A595D7 /* MGUtils.m in Sources */, 268 | 7EA83BF7225D8CE600A595D7 /* MGTask.m in Sources */, 269 | 7E3B7B20225A48C100261F51 /* ViewController.m in Sources */, 270 | 7E3B7B2B225A48C300261F51 /* main.m in Sources */, 271 | 7EA83BF4225D8CC600A595D7 /* MGRequest.m in Sources */, 272 | 7EA83BF1225D8CC600A595D7 /* MGError.m in Sources */, 273 | 7E3B7B1D225A48C100261F51 /* AppDelegate.m in Sources */, 274 | ); 275 | runOnlyForDeploymentPostprocessing = 0; 276 | }; 277 | /* End PBXSourcesBuildPhase section */ 278 | 279 | /* Begin PBXVariantGroup section */ 280 | 7E3B7B21225A48C100261F51 /* Main.storyboard */ = { 281 | isa = PBXVariantGroup; 282 | children = ( 283 | 7E3B7B22225A48C100261F51 /* Base */, 284 | ); 285 | name = Main.storyboard; 286 | sourceTree = ""; 287 | }; 288 | 7E3B7B26225A48C300261F51 /* LaunchScreen.storyboard */ = { 289 | isa = PBXVariantGroup; 290 | children = ( 291 | 7E3B7B27225A48C300261F51 /* Base */, 292 | ); 293 | name = LaunchScreen.storyboard; 294 | sourceTree = ""; 295 | }; 296 | /* End PBXVariantGroup section */ 297 | 298 | /* Begin XCBuildConfiguration section */ 299 | 7E3B7B2C225A48C300261F51 /* Debug */ = { 300 | isa = XCBuildConfiguration; 301 | buildSettings = { 302 | ALWAYS_SEARCH_USER_PATHS = NO; 303 | CLANG_ANALYZER_NONNULL = YES; 304 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 305 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 306 | CLANG_CXX_LIBRARY = "libc++"; 307 | CLANG_ENABLE_MODULES = YES; 308 | CLANG_ENABLE_OBJC_ARC = YES; 309 | CLANG_ENABLE_OBJC_WEAK = YES; 310 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 311 | CLANG_WARN_BOOL_CONVERSION = YES; 312 | CLANG_WARN_COMMA = YES; 313 | CLANG_WARN_CONSTANT_CONVERSION = YES; 314 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 315 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 316 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 317 | CLANG_WARN_EMPTY_BODY = YES; 318 | CLANG_WARN_ENUM_CONVERSION = YES; 319 | CLANG_WARN_INFINITE_RECURSION = YES; 320 | CLANG_WARN_INT_CONVERSION = YES; 321 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 323 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 325 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 326 | CLANG_WARN_STRICT_PROTOTYPES = YES; 327 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 328 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 329 | CLANG_WARN_UNREACHABLE_CODE = YES; 330 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 331 | CODE_SIGN_IDENTITY = "iPhone Developer"; 332 | COPY_PHASE_STRIP = NO; 333 | DEBUG_INFORMATION_FORMAT = dwarf; 334 | ENABLE_STRICT_OBJC_MSGSEND = YES; 335 | ENABLE_TESTABILITY = YES; 336 | GCC_C_LANGUAGE_STANDARD = gnu11; 337 | GCC_DYNAMIC_NO_PIC = NO; 338 | GCC_NO_COMMON_BLOCKS = YES; 339 | GCC_OPTIMIZATION_LEVEL = 0; 340 | GCC_PREPROCESSOR_DEFINITIONS = ( 341 | "DEBUG=1", 342 | "$(inherited)", 343 | ); 344 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 345 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 346 | GCC_WARN_UNDECLARED_SELECTOR = YES; 347 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 348 | GCC_WARN_UNUSED_FUNCTION = YES; 349 | GCC_WARN_UNUSED_VARIABLE = YES; 350 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 351 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 352 | MTL_FAST_MATH = YES; 353 | ONLY_ACTIVE_ARCH = YES; 354 | SDKROOT = iphoneos; 355 | }; 356 | name = Debug; 357 | }; 358 | 7E3B7B2D225A48C300261F51 /* Release */ = { 359 | isa = XCBuildConfiguration; 360 | buildSettings = { 361 | ALWAYS_SEARCH_USER_PATHS = NO; 362 | CLANG_ANALYZER_NONNULL = YES; 363 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 364 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 365 | CLANG_CXX_LIBRARY = "libc++"; 366 | CLANG_ENABLE_MODULES = YES; 367 | CLANG_ENABLE_OBJC_ARC = YES; 368 | CLANG_ENABLE_OBJC_WEAK = YES; 369 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 370 | CLANG_WARN_BOOL_CONVERSION = YES; 371 | CLANG_WARN_COMMA = YES; 372 | CLANG_WARN_CONSTANT_CONVERSION = YES; 373 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 374 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 375 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 376 | CLANG_WARN_EMPTY_BODY = YES; 377 | CLANG_WARN_ENUM_CONVERSION = YES; 378 | CLANG_WARN_INFINITE_RECURSION = YES; 379 | CLANG_WARN_INT_CONVERSION = YES; 380 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 381 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 382 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 383 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 384 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 385 | CLANG_WARN_STRICT_PROTOTYPES = YES; 386 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 387 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 388 | CLANG_WARN_UNREACHABLE_CODE = YES; 389 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 390 | CODE_SIGN_IDENTITY = "iPhone Developer"; 391 | COPY_PHASE_STRIP = NO; 392 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 393 | ENABLE_NS_ASSERTIONS = NO; 394 | ENABLE_STRICT_OBJC_MSGSEND = YES; 395 | GCC_C_LANGUAGE_STANDARD = gnu11; 396 | GCC_NO_COMMON_BLOCKS = YES; 397 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 398 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 399 | GCC_WARN_UNDECLARED_SELECTOR = YES; 400 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 401 | GCC_WARN_UNUSED_FUNCTION = YES; 402 | GCC_WARN_UNUSED_VARIABLE = YES; 403 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 404 | MTL_ENABLE_DEBUG_INFO = NO; 405 | MTL_FAST_MATH = YES; 406 | SDKROOT = iphoneos; 407 | VALIDATE_PRODUCT = YES; 408 | }; 409 | name = Release; 410 | }; 411 | 7E3B7B2F225A48C300261F51 /* Debug */ = { 412 | isa = XCBuildConfiguration; 413 | baseConfigurationReference = 7481E0DBC8054AF227AA4518 /* Pods-MobileGestaltDemo.debug.xcconfig */; 414 | buildSettings = { 415 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 416 | CODE_SIGN_STYLE = Manual; 417 | DEVELOPMENT_TEAM = D225N2EYEE; 418 | INFOPLIST_FILE = MobileGestaltDemo/Info.plist; 419 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 420 | LD_RUNPATH_SEARCH_PATHS = ( 421 | "$(inherited)", 422 | "@executable_path/Frameworks", 423 | ); 424 | PRODUCT_BUNDLE_IDENTIFIER = com.unique.MobileGestaltDemo; 425 | PRODUCT_NAME = "$(TARGET_NAME)"; 426 | PROVISIONING_PROFILE_SPECIFIER = luckyAllCanrundev; 427 | TARGETED_DEVICE_FAMILY = "1,2"; 428 | }; 429 | name = Debug; 430 | }; 431 | 7E3B7B30225A48C300261F51 /* Release */ = { 432 | isa = XCBuildConfiguration; 433 | baseConfigurationReference = 7A2249673B1C4E8A792C1987 /* Pods-MobileGestaltDemo.release.xcconfig */; 434 | buildSettings = { 435 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 436 | CODE_SIGN_STYLE = Manual; 437 | DEVELOPMENT_TEAM = D225N2EYEE; 438 | INFOPLIST_FILE = MobileGestaltDemo/Info.plist; 439 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 440 | LD_RUNPATH_SEARCH_PATHS = ( 441 | "$(inherited)", 442 | "@executable_path/Frameworks", 443 | ); 444 | PRODUCT_BUNDLE_IDENTIFIER = com.unique.MobileGestaltDemo; 445 | PRODUCT_NAME = "$(TARGET_NAME)"; 446 | PROVISIONING_PROFILE_SPECIFIER = luckyAllCanrundev; 447 | TARGETED_DEVICE_FAMILY = "1,2"; 448 | }; 449 | name = Release; 450 | }; 451 | /* End XCBuildConfiguration section */ 452 | 453 | /* Begin XCConfigurationList section */ 454 | 7E3B7B13225A48C100261F51 /* Build configuration list for PBXProject "MobileGestaltDemo" */ = { 455 | isa = XCConfigurationList; 456 | buildConfigurations = ( 457 | 7E3B7B2C225A48C300261F51 /* Debug */, 458 | 7E3B7B2D225A48C300261F51 /* Release */, 459 | ); 460 | defaultConfigurationIsVisible = 0; 461 | defaultConfigurationName = Release; 462 | }; 463 | 7E3B7B2E225A48C300261F51 /* Build configuration list for PBXNativeTarget "MobileGestaltDemo" */ = { 464 | isa = XCConfigurationList; 465 | buildConfigurations = ( 466 | 7E3B7B2F225A48C300261F51 /* Debug */, 467 | 7E3B7B30225A48C300261F51 /* Release */, 468 | ); 469 | defaultConfigurationIsVisible = 0; 470 | defaultConfigurationName = Release; 471 | }; 472 | /* End XCConfigurationList section */ 473 | }; 474 | rootObject = 7E3B7B10225A48C100261F51 /* Project object */; 475 | } 476 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo.xcodeproj/xcshareddata/xcschemes/MobileGestaltDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/7. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/7. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 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 YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 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 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 52 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 76 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleURLTypes 20 | 21 | 22 | CFBundleTypeRole 23 | Editor 24 | CFBundleURLName 25 | MobileGestalt 26 | CFBundleURLSchemes 27 | 28 | mobilegestalt 29 | 30 | 31 | 32 | CFBundleVersion 33 | 1 34 | LSRequiresIPhoneOS 35 | 36 | UILaunchStoryboardName 37 | LaunchScreen 38 | UIMainStoryboardFile 39 | Main 40 | UIRequiredDeviceCapabilities 41 | 42 | armv7 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UISupportedInterfaceOrientations~ipad 51 | 52 | UIInterfaceOrientationPortrait 53 | UIInterfaceOrientationPortraitUpsideDown 54 | UIInterfaceOrientationLandscapeLeft 55 | UIInterfaceOrientationLandscapeRight 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/7. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UITableViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/7. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "MobileGestalt.h" 11 | #import 12 | 13 | #define UDK_DATA @"com.unique.mobilegestalt.demo.data" 14 | 15 | @interface ViewController () 16 | 17 | @property (nonatomic, strong, readonly) MGSession *session; 18 | 19 | @property (nonatomic, strong) NSDictionary *data; 20 | 21 | @property (nonatomic, strong) NSError *error; 22 | 23 | @end 24 | 25 | @implementation ViewController 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | // Do any additional setup after loading the view. 30 | 31 | MGSessionConfiguration *configuration = [MGSessionConfiguration defaultConfiguration]; 32 | configuration.port = 10418; 33 | configuration.log = YES; 34 | _session = [MGSession sessionWithConfiguration:configuration]; 35 | 36 | if (self.session.error) { 37 | self.error = self.session.error; 38 | } 39 | } 40 | 41 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 42 | NSInteger sections = 1; 43 | if (self.data || self.error) { 44 | sections++; 45 | } 46 | return sections; 47 | } 48 | 49 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 50 | if (section == 0) { 51 | return 2; 52 | } else { 53 | return self.data ? 5 : 3; 54 | } 55 | } 56 | 57 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 58 | if (section == 0) { 59 | return @"OPERATION"; 60 | } else { 61 | if (self.data) { 62 | return @"DEVICE INFORMATION"; 63 | } else { 64 | return @"ERROR"; 65 | } 66 | } 67 | } 68 | 69 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 70 | if (indexPath.section == 0) { 71 | UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"GET" forIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; 72 | if (indexPath.row == 0) { 73 | cell.textLabel.text = @"Get Device Information (no sign)"; 74 | } else { 75 | cell.textLabel.text = @"Get Device Information (sign)"; 76 | } 77 | return cell; 78 | } else if (self.data) { 79 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"INFO" forIndexPath:indexPath]; 80 | NSArray *titles = @[MGAttributeUDID, MGAttributeIMEI, MGAttributeICCID, MGAttributeProduct, MGAttributeVersion]; 81 | NSString *key = titles[indexPath.row]; 82 | cell.textLabel.text = key; 83 | cell.detailTextLabel.text = self.data[key]; 84 | return cell; 85 | } else { 86 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ERROR" forIndexPath:indexPath]; 87 | NSArray *titles = @[@"Description", @"Reason", @"Suggestion"]; 88 | NSMutableDictionary *subtitles = [NSMutableDictionary dictionary]; 89 | subtitles[@"Description"] = self.error.localizedDescription; 90 | subtitles[@"Reason"] = self.error.localizedFailureReason; 91 | subtitles[@"Suggestion"] = self.error.localizedRecoverySuggestion; 92 | 93 | NSString *key = titles[indexPath.row]; 94 | cell.textLabel.text = key; 95 | cell.detailTextLabel.text = subtitles[key]; 96 | return cell; 97 | } 98 | } 99 | 100 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 101 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 102 | if (indexPath.section == 0) { 103 | MGRequest *request = nil; 104 | if (indexPath.row == 0) { 105 | request = [MGRequest requestWithTitle:@"MGTitle" subtitle:@"MGSubtitle" description:@"MGDescritpion"]; 106 | } else { 107 | NSString *path = [NSBundle.mainBundle pathForResource:@"sign" ofType:@"mobileconfig"]; 108 | NSData *data = [NSData dataWithContentsOfFile:path]; 109 | request = [MGRequest requestWithMobileConfigData:data]; 110 | } 111 | [self.session request:request completed:^(MGRequest *request, MGResponse *response, NSError *error) { 112 | self.data = nil; 113 | self.error = nil; 114 | if (response.data) { 115 | self.data = response.data; 116 | } else { 117 | self.error = error; 118 | } 119 | [self.tableView reloadData]; 120 | }]; 121 | } 122 | } 123 | 124 | @end 125 | -------------------------------------------------------------------------------- /MobileGestaltDemo/MobileGestaltDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MobileGestaltDemo 4 | // 5 | // Created by Magic-Unique on 2019/4/7. 6 | // Copyright © 2019 Magic-Unique. All rights reserved. 7 | // 8 | 9 | #import 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 | } 17 | -------------------------------------------------------------------------------- /MobileGestaltDemo/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | inhibit_all_warnings! 5 | 6 | target 'MobileGestaltDemo' do 7 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks 8 | # use_frameworks! 9 | 10 | # Pods for MobileGestaltDemo 11 | 12 | pod 'GCDWebServer' 13 | pod 'Masonry' 14 | 15 | end 16 | -------------------------------------------------------------------------------- /MobileGestaltDemo/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - GCDWebServer (3.5.2): 3 | - GCDWebServer/Core (= 3.5.2) 4 | - GCDWebServer/Core (3.5.2) 5 | - Masonry (1.1.0) 6 | 7 | DEPENDENCIES: 8 | - GCDWebServer 9 | - Masonry 10 | 11 | SPEC REPOS: 12 | https://github.com/cocoapods/specs.git: 13 | - GCDWebServer 14 | - Masonry 15 | 16 | SPEC CHECKSUMS: 17 | GCDWebServer: ead88cd14596dd4eae4f5830b8877c87c8728990 18 | Masonry: 678fab65091a9290e40e2832a55e7ab731aad201 19 | 20 | PODFILE CHECKSUM: 1e89bf5ab28f040da7546ec6d37321298af811f8 21 | 22 | COCOAPODS: 1.5.3 23 | -------------------------------------------------------------------------------- /MobileGestaltDemo/mdm.mobileconfig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PayloadContent 6 | 7 | URL 8 | http://127.0.0.1:10418/MobileGestalt/register 9 | DeviceAttributes 10 | 11 | UDID 12 | IMEI 13 | ICCID 14 | VERSION 15 | PRODUCT 16 | 17 | 18 | PayloadOrganization 19 | Mobile Gestalt 20 | PayloadDisplayName 21 | Mobile Gestalt Demo 22 | PayloadVersion 23 | 1 24 | PayloadUUID 25 | 3C4DC7D2-E475-3375-489C-0BB8D737A653 26 | PayloadIdentifier 27 | com.unique.mobilegestalt.register 28 | PayloadDescription 29 | Get device information 30 | PayloadType 31 | Profile Service 32 | 33 | -------------------------------------------------------------------------------- /MobileGestaltDemo/sign.mobileconfig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Magic-Unique/MobileGestalt/b8bc76143d06d272f9aa53194edbb6d942bae9e3/MobileGestaltDemo/sign.mobileconfig -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MobileGestalt 2 | 3 | Get iOS device UDID with public API 4 | 5 | ## How it works? 6 | 7 | The library use *.mobileconfig file to get device information. You can read the [documents](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/ConfigurationProfileExamples/ConfigurationProfileExamples.html) by Apple to learn about. 8 | 9 | ## What can we get? 10 | 11 | * UDID 12 | * IMEI 13 | * ICCID (I can't got it but write in the documents by Apple) 14 | * Products (Like: **iPhone8,3**) 15 | * Version (Like: **14G60**) 16 | 17 | ## Can use in App Store? 18 | 19 | > Sorry, I don't know. 20 | 21 | ## USAGE - QUICK 22 | 23 | ### 1. Install 24 | 25 | 1. Use CocoaPods `pod 'MobileGestalt'` 26 | 2. Use Source, drag *MobileGestalt* to your project 27 | 28 | Import 29 | 30 | ```objc 31 | #import 32 | ``` 33 | 34 | ### 2. Add URL Scheme 35 | 36 | Add an unique URLScheme to your *Info.plist*. 37 | 38 | Such as: `mobilegestalt` 39 | 40 | ### 3. Create a session 41 | 42 | ```objc 43 | MGSessionConfiguration *configuration = [MGSessionConfiguration defaultConfiguration]; 44 | configuration.port = 10418; 45 | configuration.portOffset = 3; // Use port 10418~10421 46 | 47 | configuration.port = 0; // Use random port 48 | self.session = [MGSession sessionWithConfiguration:configuration]; 49 | ``` 50 | 51 | ### 4. Create a request 52 | 53 | ```objc 54 | // Create a custom request 55 | MGRequest *request = [MGRequest request]; 56 | request.attributes = @[MGAttributeUDID, MGAttributeIMEI, MGAttributeICCID, MGAttributeVersion, MGAttributeProduct]; 57 | request.displayName = @"Title for Profile"; 58 | request.organization = @"Subtitle for Profile"; 59 | request.explain = @"Description for Profile"; 60 | request.identifier = @"com.unique.mobilegestalt"; 61 | 62 | // Create a signed request in remote 63 | MGRequest *request = [MGRequest requestWithMobileConfigURL:aRemoteURL]; 64 | 65 | // Create a signed request in local 66 | MGRequest *request = [MGRequest requestWithMobileConfigData:aNSData]; 67 | 68 | ``` 69 | 70 | ### 5. Send request 71 | 72 | ```objc 73 | [self.session request:request completed:^(MGRequest *request, MGResponse *response, NSError *error) { 74 | if (error) { 75 | NSLog(@"%@", error); 76 | } else { 77 | NSLog(@"%@", response.data); 78 | } 79 | }]; 80 | ``` 81 | 82 | --------------------------------------------------------------------------------