第十八篇、keychain保存UUID(保持唯一性,应用卸载,下载安装也不变)和获取IP地址
.h
#import <Foundation/Foundation.h>
#import <Security/Security.h> /**使用**/
//-(void) setKeyChainValue
//{
// KeychainItemWrapper *keyChainItem=[[KeychainItemWrapper alloc]initWithIdentifier:@"TestUUID" accessGroup:@"XXXXXX.h.HelloWorld"];
// NSString *strUUID = [keyChainItem objectForKey:(id)kSecValueData];
// if (strUUID==nil||[strUUID isEqualToString:@""])
// {
// [keyChainItem setObject:[self gen_uuid] forKey:(id)kSecValueData];
// }
// [keyChainItem release];
//
//}
//
//-(NSString *) gen_uuid
//{
// CFUUIDRef uuid_ref=CFUUIDCreate(nil);
// CFStringRef uuid_string_ref=CFUUIDCreateString(nil, uuid_ref);
// CFRelease(uuid_ref);
// NSString *uuid=[NSString stringWithString:uuid_string_ref];
// CFRelease(uuid_string_ref);
// return uuid;
//} //Define an Objective-C wrapper class to hold Keychain Services code.
@interface KeychainWrapper : NSObject {
NSMutableDictionary *keychainData;
NSMutableDictionary *genericPasswordQuery;
}
@property (nonatomic, strong) NSMutableDictionary *keychainData;
@property (nonatomic, strong) NSMutableDictionary *genericPasswordQuery; - (void)mySetObject:(id)inObject forKey:(id)key;
- (id)myObjectForKey:(id)key;
- (void)resetKeychainItem; +(instancetype) shareManager;
/**获取唯一的UUID**/
-(NSString *) KeyChainValue;
@end
.m
#import "KeychainWrapper.h" /* ********************************************************************** */
//Unique string used to identify the keychain item:
static const UInt8 kKeychainItemIdentifier[] = "com.apple.dts.KeychainUI\0"; @interface KeychainWrapper (PrivateMethods) //The following two methods translate dictionaries between the format used by
// the view controller (NSString *) and the Keychain Services API:
- (NSMutableDictionary *)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert;
- (NSMutableDictionary *)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert;
// Method used to write data to the keychain:
- (void)writeToKeychain; @end @implementation KeychainWrapper //Synthesize the getter and setter:
@synthesize keychainData, genericPasswordQuery; static KeychainWrapper *manager = nil;
+(instancetype) shareManager
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[KeychainWrapper alloc]init];
});
return manager; } /**获取唯一的UUID**/
-(NSString *) KeyChainValue
{
NSString *strUUID = [self myObjectForKey:(id)kSecValueData];
if (strUUID==nil||[strUUID isEqualToString:@""])
{
[self mySetObject:[self uuid] forKey:(id)kSecValueData];
strUUID = [self uuid]; // 首次获取为空,需要赋值
}
return strUUID;
} -(NSString*) uuid {
CFUUIDRef puuid = CFUUIDCreate( nil );
CFStringRef uuidString = CFUUIDCreateString( nil, puuid );
NSString * result = (NSString *)CFBridgingRelease(CFStringCreateCopy( NULL, uuidString));
CFRelease(puuid);
CFRelease(uuidString);
return result;
} - (id)init
{
if ((self = [super init])) { OSStatus keychainErr = noErr;
// Set up the keychain search dictionary:
genericPasswordQuery = [[NSMutableDictionary alloc] init];
// This keychain item is a generic password.
[genericPasswordQuery setObject:(__bridge id)kSecClassGenericPassword
forKey:(__bridge id)kSecClass];
// The kSecAttrGeneric attribute is used to store a unique string that is used
// to easily identify and find this keychain item. The string is first
// converted to an NSData object:
NSData *keychainItemID = [NSData dataWithBytes:kKeychainItemIdentifier
length:strlen((const char *)kKeychainItemIdentifier)];
[genericPasswordQuery setObject:keychainItemID forKey:(__bridge id)kSecAttrGeneric];
// Return the attributes of the first match only:
[genericPasswordQuery setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
// Return the attributes of the keychain item (the password is
// acquired in the secItemFormatToDictionary: method):
[genericPasswordQuery setObject:(__bridge id)kCFBooleanTrue
forKey:(__bridge id)kSecReturnAttributes]; //Initialize the dictionary used to hold return data from the keychain:
CFMutableDictionaryRef outDictionary = nil;
// If the keychain item exists, return the attributes of the item:
keychainErr = SecItemCopyMatching((__bridge CFDictionaryRef)genericPasswordQuery,
(CFTypeRef *)&outDictionary);
if (keychainErr == noErr) {
// Convert the data dictionary into the format used by the view controller:
self.keychainData = [self secItemFormatToDictionary:(__bridge_transfer NSMutableDictionary *)outDictionary];
} else if (keychainErr == errSecItemNotFound) {
// Put default values into the keychain if no matching
// keychain item is found:
[self resetKeychainItem];
if (outDictionary) CFRelease(outDictionary);
} else {
// Any other error is unexpected.
NSAssert(NO, @"Serious error.\n");
if (outDictionary) CFRelease(outDictionary);
}
}
return self;
} // Implement the mySetObject:forKey method, which writes attributes to the keychain:
- (void)mySetObject:(id)inObject forKey:(id)key
{
if (inObject == nil) return;
id currentObject = [keychainData objectForKey:key];
if (![currentObject isEqual:inObject])
{
[keychainData setObject:inObject forKey:key];
[self writeToKeychain];
}
} // Implement the myObjectForKey: method, which reads an attribute value from a dictionary:
- (id)myObjectForKey:(id)key
{
return [keychainData objectForKey:key];
} // Reset the values in the keychain item, or create a new item if it
// doesn't already exist: - (void)resetKeychainItem
{
if (!keychainData) //Allocate the keychainData dictionary if it doesn't exist yet.
{
self.keychainData = [[NSMutableDictionary alloc] init];
}
else if (keychainData)
{
// Format the data in the keychainData dictionary into the format needed for a query
// and put it into tmpDictionary:
NSMutableDictionary *tmpDictionary =
[self dictionaryToSecItemFormat:keychainData];
// Delete the keychain item in preparation for resetting the values:
OSStatus errorcode = SecItemDelete((__bridge CFDictionaryRef)tmpDictionary);
NSAssert(errorcode == noErr, @"Problem deleting current keychain item." );
} // Default generic data for Keychain Item:
// [keychainData setObject:@"Item label" forKey:(__bridge id)kSecAttrLabel];
// [keychainData setObject:@"Item description" forKey:(__bridge id)kSecAttrDescription];
// [keychainData setObject:@"Account" forKey:(__bridge id)kSecAttrAccount];
// [keychainData setObject:@"Service" forKey:(__bridge id)kSecAttrService];
// [keychainData setObject:@"Your comment here." forKey:(__bridge id)kSecAttrComment];
// [keychainData setObject:@"password" forKey:(__bridge id)kSecValueData];
} // Implement the dictionaryToSecItemFormat: method, which takes the attributes that
// you want to add to the keychain item and sets up a dictionary in the format
// needed by Keychain Services:
- (NSMutableDictionary *)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert
{
// This method must be called with a properly populated dictionary
// containing all the right key/value pairs for a keychain item search. // Create the return dictionary:
NSMutableDictionary *returnDictionary =
[NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert]; // Add the keychain item class and the generic attribute:
NSData *keychainItemID = [NSData dataWithBytes:kKeychainItemIdentifier
length:strlen((const char *)kKeychainItemIdentifier)];
[returnDictionary setObject:keychainItemID forKey:(__bridge id)kSecAttrGeneric];
[returnDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; // Convert the password NSString to NSData to fit the API paradigm:
NSString *passwordString = [dictionaryToConvert objectForKey:(__bridge id)kSecValueData];
[returnDictionary setObject:[passwordString dataUsingEncoding:NSUTF8StringEncoding]
forKey:(__bridge id)kSecValueData];
return returnDictionary;
} // Implement the secItemFormatToDictionary: method, which takes the attribute dictionary
// obtained from the keychain item, acquires the password from the keychain, and
// adds it to the attribute dictionary:
- (NSMutableDictionary *)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert
{
// This method must be called with a properly populated dictionary
// containing all the right key/value pairs for the keychain item. // Create a return dictionary populated with the attributes:
NSMutableDictionary *returnDictionary = [NSMutableDictionary
dictionaryWithDictionary:dictionaryToConvert]; // To acquire the password data from the keychain item,
// first add the search key and class attribute required to obtain the password:
[returnDictionary setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
[returnDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
// Then call Keychain Services to get the password:
CFDataRef passwordData = NULL;
OSStatus keychainError = noErr; //
keychainError = SecItemCopyMatching((__bridge CFDictionaryRef)returnDictionary,
(CFTypeRef *)&passwordData);
if (keychainError == noErr)
{
// Remove the kSecReturnData key; we don't need it anymore:
[returnDictionary removeObjectForKey:(__bridge id)kSecReturnData]; // Convert the password to an NSString and add it to the return dictionary:
NSString *password = [[NSString alloc] initWithBytes:[(__bridge_transfer NSData *)passwordData bytes]
length:[(__bridge NSData *)passwordData length] encoding:NSUTF8StringEncoding];
[returnDictionary setObject:password forKey:(__bridge id)kSecValueData];
}
// Don't do anything if nothing is found.
else if (keychainError == errSecItemNotFound) {
NSAssert(NO, @"Nothing was found in the keychain.\n");
if (passwordData) CFRelease(passwordData);
}
// Any other error is unexpected.
else
{
NSAssert(NO, @"Serious error.\n");
if (passwordData) CFRelease(passwordData);
} return returnDictionary;
} // Implement the writeToKeychain method, which is called by the mySetObject routine,
// which in turn is called by the UI when there is new data for the keychain. This
// method modifies an existing keychain item, or--if the item does not already
// exist--creates a new keychain item with the new attribute value plus
// default values for the other attributes.
- (void)writeToKeychain
{
CFDictionaryRef attributes = nil;
NSMutableDictionary *updateItem = nil; // If the keychain item already exists, modify it:
if (SecItemCopyMatching((__bridge CFDictionaryRef)genericPasswordQuery,
(CFTypeRef *)&attributes) == noErr)
{
// First, get the attributes returned from the keychain and add them to the
// dictionary that controls the update:
updateItem = [NSMutableDictionary dictionaryWithDictionary:(__bridge_transfer NSDictionary *)attributes]; // Second, get the class value from the generic password query dictionary and
// add it to the updateItem dictionary:
[updateItem setObject:[genericPasswordQuery objectForKey:(__bridge id)kSecClass]
forKey:(__bridge id)kSecClass]; // Finally, set up the dictionary that contains new values for the attributes:
NSMutableDictionary *tempCheck = [self dictionaryToSecItemFormat:keychainData];
//Remove the class--it's not a keychain attribute:
[tempCheck removeObjectForKey:(__bridge id)kSecClass]; // You can update only a single keychain item at a time.
OSStatus errorcode = SecItemUpdate(
(__bridge CFDictionaryRef)updateItem,
(__bridge CFDictionaryRef)tempCheck);
NSAssert(errorcode == noErr, @"Couldn't update the Keychain Item." );
}
else
{
// No previous item found; add the new item.
// The new value was added to the keychainData dictionary in the mySetObject routine,
// and the other values were added to the keychainData dictionary previously.
// No pointer to the newly-added items is needed, so pass NULL for the second parameter:
OSStatus errorcode = SecItemAdd(
(__bridge CFDictionaryRef)[self dictionaryToSecItemFormat:keychainData],
NULL);
NSAssert(errorcode == noErr, @"Couldn't add the Keychain Item." );
if (attributes) CFRelease(attributes);
}
} @end
获取设备的IP地址
#import "getIPhoneIP.h"
#import <ifaddrs.h>
#import <arpa/inet.h> @implementation getIPhoneIP
//create by huangys
+(NSString *)getIPAddress {
NSString *address = @"error";
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
int success = ;
// retrieve the current interfaces - returns 0 on success
success = getifaddrs(&interfaces);
if (success == ) {
// Loop through linked list of interfaces
temp_addr = interfaces;
while(temp_addr != NULL) {
if(temp_addr->ifa_addr->sa_family == AF_INET) {
// Check if interface is en0 which is the wifi connection on the iPhone
if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
// Get NSString from C String
address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
}
}
temp_addr = temp_addr->ifa_next;
}
}
// Free memory
freeifaddrs(interfaces);
return address;
}
@end
第十八篇、keychain保存UUID(保持唯一性,应用卸载,下载安装也不变)和获取IP地址的更多相关文章
- Python之路【第十八篇】:Web框架们
Python之路[第十八篇]:Web框架们 Python的WEB框架 Bottle Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Pytho ...
- Egret入门学习日记 --- 第十八篇(书中 8.5~8.7 节 内容)
第十八篇(书中 8.5~8.7 节 内容) 其实语法篇,我感觉没必要写录入到日记里. 我也犹豫了好久,到底要不要录入. 这样,我先读一遍语法篇的所有内容,我觉得值得留下的,我就录入日记里. 不然像昨天 ...
- 第八篇 :微信公众平台开发实战Java版之如何网页授权获取用户基本信息
第一部分:微信授权获取基本信息的介绍 我们首先来看看官方的文档怎么说: 如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑. 关于网页授权回调域 ...
- Python开发【第十八篇】Web框架之Django【基础篇】
一.简介 Python下有许多款不同的 Web 框架,Django 是重量级选手中最有代表性的一位,许多成功的网站和APP都基于 Django. Django 是一个开放源代码的Web应用框架,由 P ...
- Android UI开发第二十八篇——Fragment中使用左右滑动菜单
Fragment实现了Android UI的分片管理,尤其在平板开发中,好处多多.这一篇将借助Android UI开发第二十六篇——Fragment间的通信. Android UI开发第二十七篇——实 ...
- 【Python之路】第十八篇--MySQL(一)
一.概述 1.什么是数据库 ? 答:数据的仓库. 2.什么是 MySQL.Oracle.SQLite.Access.MS SQL Server等 ? 答:他们均是一个软件,都有两个主要的功能: a. ...
- 第十八篇 ANDROID的声音管理系统及服务
声音管理系统用来实现声音的输入和输出.声音的控制和路由等功能,包括主和各种音源的音量调节.声音焦点控制,声音外设的检测和状态管理,声音源输入和输出的策略管理.音效的播放.音轨设置和播放.录音设置 ...
- spring-第十八篇之spring AOP基于XML配置文件的管理方式
1.在XML配置文件中配置切面.切入点.增强处理.spring-1.5之前只能使用XML Schema方式配置切面.切入点.增强处理. spring配置文件中,所有的切面.切入点.增强处理都必须定义在 ...
- Python之路【第十八篇】Django小项目webQQ实现
WEBQQ的实现的几种方式 1.HTTP协议特点 首先这里要知道HTTP协议的特点:短链接.无状态! 在不考虑本地缓存的情况举例来说:咱们在连接博客园的时候,当tcp连接后,我会把我自己的http头发 ...
随机推荐
- hdoj 1262 寻找素数对
寻找素数对 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submi ...
- Web 应用的安全性
Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分.用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统.用户授权 ...
- 关系数据库 范式(NF: Normal Form) 说明
关系数据库 范式(NF: Normal Form) 说明 数据库电话insertdelete存储oracle 目录(?)[+] 一.范式概述(NF:NormalForm) 数据库的设计范式是数 ...
- Spring + iBatis 的多库横向切分简易解决思路
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- Java获取时间与系统时间相差8小时终极解决方案
一.在取日期以前设置一下时区 TimeZone tz = TimeZone.getTimeZone(“ETC/GMT-8″);TimeZone.setDefault(tz); 此种方法适用于单次快速获 ...
- git reset and git checkout
git reset --hard <commit>: 1.替换引用的指向.引用指向新的提交ID; 2.替换暂存区.替换后,暂存区的内容和引用指向的文件夹树一致; 3.替换工作区.替换后,工 ...
- To Noob Json是什么鬼?
转载请注明出处王亟亟的大牛之路 供应商A:那我们数据怎么交互啊?HTTP吧?那内容呢?JSON?XML? 小菜鸟B:JSON什么鬼? 为了菜鸟们避免以上情况楼主写一发JSON的博文,废话不多!開始! ...
- android图片处理方法(不断收集中)
//压缩图片大小 public static Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ByteArr ...
- [ES6] ES6 Parameter Object Destructuring with Required Values
Not only can you provide default values when using ES6 parameter object destructuring, but you can a ...
- 如何打开“USB调试”模式?
请首先确认您的系统版本, 点击「设置」-「关于手机」查看您当前的手机版本号. 如果您使用的是 Android 3.2及以下系统,请按以下步骤操作: STEP1:在应用列表选择「设置」进入系统设置菜单: ...