Reputation: 1026
In my Xamarin iOS app, I am storing the DeviceId and AccessToken in the keychain. For saving and retrieving the access token my code works fine, but for the device id(It is a GUID) on saving the device-id it gives the result as DuplicateItem
, and on retrieving the device-id it gives the result as ItemNotFound
. I am using seperate keys for device Id and access token. Here is my code
public const string DEVICE_ID = "DEVICE_ID";
public const string ACCESS_TOKEN = "ACCESS_TOKEN";
public static string GetValue(string key)
{
var query = new SecRecord(SecKind.GenericPassword)
{
Generic = NSData.FromString(key)
};
SecStatusCode result;
var match = SecKeyChain.QueryAsRecord(query, out result);
if (result == SecStatusCode.Success)
{
return match.ValueData.ToString();
}
return string.Empty;
}
public static void SetValue(string value, string key)
{
var query = new SecRecord(SecKind.GenericPassword)
{
ValueData = NSData.FromString(value),
Generic = NSData.FromString(key)
};
var result = SecKeyChain.Add(query);
}
I save and get the device id by the method calls like
SetValue(Guid.NewGuid(), DEVICE_ID);
string deviceId = GetValue(DEVICE_ID);
It may look weird but I don't know why it is behaving like this, Does anyone had experienced this issue or Is there any error in my code. Please help me.
Upvotes: 0
Views: 546
Reputation: 3276
This is our class for storing and retrieving from the SecKeyChain, I'd suggest using ours and see if you get the same results.
using Security;
using Foundation;
public class KeyChain
{
public const string DEVICE_ID = "DEVICE_ID";
public const string ACCESS_TOKEN = "ACCESS_TOKEN";
public string ValueForKey(string key)
{
var record = ExistingRecordForKey (key);
SecStatusCode resultCode;
var match = SecKeyChain.QueryAsRecord(record, out resultCode);
if (resultCode == SecStatusCode.Success)
return NSString.FromData (match.ValueData, NSStringEncoding.UTF8);
else
return String.Empty;
}
public void SetValueForKey(string value, string key)
{
var record = ExistingRecordForKey (key);
if (value.IsNullOrEmpty())
{
if (!ValueForKey(key).IsNullOrEmpty())
RemoveRecord(record);
return;
}
// if the key already exists, remove it
if (!ValueForKey(key).IsNullOrEmpty())
RemoveRecord(record);
var result = SecKeyChain.Add(CreateRecordForNewKeyValue(key, value));
if (result != SecStatusCode.Success)
{
throw new Exception(String.Format("Error adding record: {0}", result));
}
}
private SecRecord CreateRecordForNewKeyValue(string key, string value)
{
return new SecRecord(SecKind.GenericPassword)
{
Account = key,
Service = ServiceName,
Label = key,
ValueData = NSData.FromString(value, NSStringEncoding.UTF8),
};
}
private SecRecord ExistingRecordForKey(string key)
{
return new SecRecord(SecKind.GenericPassword)
{
Account = key,
Service = ServiceName,
Label = key,
};
}
private bool RemoveRecord(SecRecord record)
{
var result = SecKeyChain.Remove(record);
if (result != SecStatusCode.Success)
{
throw new Exception(String.Format("Error removing record: {0}", result));
}
return true;
}
}
Then the class and or method that you want to retrieve the information from would look like this:
public class OtherClass
{
Public void GetInfo()
{
// Store device id
KeyChain.SetValueForKey(Guid.NewGuid(), KeyChain.DEVICE_ID);
// Retrieve device id
string value = KeyChain.ValueForKey(DEVICE_ID);
// Store access token
KeyChain.SetValueForKey(Guid.NewGuid(), KeyChain.ACCESS_TOKEN);
// Retrie acce token
string value = KeyChain.ValueForKey(ACCESS_TOKEN);
}
}
Upvotes: 2