Firemonkey扩展增强: iOS 访问钥匙串Keychain

项目中需要区分iOS设备,但是苹果已经封了获取UDID和MAC的API,目前可行的方案是在钥匙串Keychain中存储自己产生的唯一标识,如GUID。

关于iOS的唯一标识技术解决方案比较参见:这里

苹果官方钥匙串开发指导参见Keychain Services Programming Guide

Firemonkey目前并没有为我们封装好Security.framework,看了苹果官方的使用示例,发现自己Wrapper太麻烦。网上找了下,发现一个开源项目的代码比较简单明了,是OC编写的,拿来修改一下编译成静态库以供Firemonkey使用。

以下是封装调用静态库的代码:下载静态库文件

使用上直接调用StoreItemToKeychain存储一对Key-Value值到钥匙串;

调用GetItemValueFromKeychain获取指定Key的Value值;

调用DeleteItemFromKeychain删除指定Key。

静态库只封装了通用密码类型,所有Key-Value都将加密存储在钥匙串中。

unit TU2.iOS.KeychainHelper;

interface

  //访问钥匙串
  function StoreItemToKeychain(const AServiceName, AKey, AValue: string; const bOverride: Boolean=True): Boolean;
  function GetItemValueFromKeychain(const AServiceName, AKey: string): string;
  function DeleteItemFromKeychain(const AServiceName, AKey: string): Boolean;

implementation

uses iOSapi.Foundation, Macapi.ObjectiveC, iOSapi.CocoaTypes, Macapi.Helpers;

type
  KeychainHelper = interface(NSObject)
    ['{591C260D-D80F-44C7-9400-20D49F4B87AA}']
  end;

  KeychainHelperClass = interface(NSObjectClass)
    ['{605B4A71-35B5-4307-845D-97F6933C2A1E}']
//+ (NSString *) getPasswordForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSInteger *) error;
//+ (NSInteger) storeUsername: (NSString *) username andPassword: (NSString *) password forServiceName: (NSString *) serviceName updateExisting: (BOOL) updateExisting;
//+ (NSInteger) deleteItemForUsername: (NSString *) username andServiceName: (NSString *) serviceName;

    [MethodName('getPasswordForUsername:andServiceName:error:')]
    function getPasswordForUsernameAndServiceName(username, serviceName: NSString; error: PNSInteger): NSString; cdecl;
    [MethodName('storeUsername:andPassword:forServiceName:updateExisting:')]
    function storeUsernameAndPasswordForServiceName(username, password, serviceName: NSString; updateExisting: Boolean): NSInteger; cdecl;
    [MethodName('deleteItemForUsername:andServiceName:')]
    function deleteItemForUsernameAndServiceName(username, serviceName: NSString): NSInteger; cdecl;
  end;

  TKeychainHelper = class(TOCGenericImport<KeyChainHelperClass, KeyChainHelper>);

{$IFDEF CPUARM}
{$O-}
function KeychainHelper_FakeLoader : KeychainHelper; cdecl; external 'libKeychainHelper_iOS.a' name 'OBJC_CLASS_$_KeychainHelper';
{$O+}
{$ENDIF}

function StoreItemToKeychain(const AServiceName, AKey, AValue: string;
  const bOverride: Boolean=True): Boolean;
var
  ARet: NSInteger;
begin
  ARet := TKeychainHelper.OCClass.storeUsernameAndPasswordForServiceName(
    StrToNSStr(AKey), StrToNSStr(AValue), StrToNSStr(AServiceName), bOverride);
  Result := ARet>=0;
end;

function GetItemValueFromKeychain(const AServiceName, AKey: string): string;
var
  AValue: NSString;
  AError: NSInteger;
begin
  Result := '';
  AError := 0;
  AValue := TKeychainHelper.OCClass.getPasswordForUsernameAndServiceName(
    StrToNSStr(AKey), StrToNSStr(AServiceName), PNSInteger(@AError));
  if AError=1 then
    Result := NSStrToStr(AValue);
end;

function DeleteItemFromKeychain(const AServiceName, AKey: string): Boolean;
begin
  Result := TKeychainHelper.OCClass.deleteItemForUsernameAndServiceName(
    StrToNSStr(AKey), StrToNSStr(AServiceName))>=0;
end;

end.

 

1、Firemonkey引用iOS静态库*.a文件

无导出类型的静态库使用方法参见:这里,这里对有导出类型的静态库附加两点:

1)*.a文件只需放在工程能识别的目录下即可,不需也不能设置Deloyment到设备上,否则前期调试都没问题,发布到appstore会检测通不过(被坑过);

2)由于IDE更新很快,网上有些关于Wrapper静态库的示例提供的方式都已经不适用了。关于XXX_FakeLoader函数只需如上面代码所示申明一下即可,无需{$link XXX.a},也不需在单元初始段中调用XXX_FakeLoader。

2、如果按照网上XCode开发静态库教程编译出来的静态库在Delphi下编译发布版时报如下类似错误,是因为检测到静态库文件含有调试信息。(此问题高版本已经有解决选项

在XCode的工程中如下设置,重新编译一个Release版本即可。

 

3、以上静态库使用方法目前只对iOS设备目标平台有效,对模拟器还没有找到使用方式,如有会的请不吝赐教。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
ModernListView (Berlin, Tokyo [with fix], Rio) 很好的Delphi Firemonkey控件,可用作Android、iOS、MacOS、Windows开发,比Delphi自带的listview更好用、功能更强大! ListView1.SetColorItemSelected(TAlphaColorRec.Orangered); ListView1.SetColorItemFill(TAlphaColorRec.Whitesmoke); ListView1.SetColorItemFillAlt(TAlphaColorRec.Lightgrey); ListView1.SetColorBackground(TAlphaColorRec.Whitesmoke); ListView1.SetColorItemSeparator(TAlphaColorRec.Red); ListView1.SetColorText(TAlphaColorRec.Darkmagenta); ListView1.SetColorTextSelected(TAlphaColorRec.Blueviolet); ListView1.SetColorTextDetail(TAlphaColorRec.Darksalmon); ListView1.SetColorHeader(TAlphaColorRec.Crimson); ListView1.SetColorTextHeader(TAlphaColorRec.Whitesmoke); ListView1.SetColorTextHeaderShadow(TAlphaColorRec.grey); ListView1.SetColorPullRefresh(TAlphaColorRec.Lime); ListView1.SetColorPullRefreshIndicator(TAlphaColorRec.Limegreen); ListView1.SetColorStretchGlow(TAlphaColorRec.Limegreen); Style for ListView Columns Mode ListView1.ShowScrollBar - hide/show scrollbar ListView1.ItemsClearTrue - correct delete items ListView1.OffsetTop - indent of the first element ListView1.OffsetBottom - indent of the last element ListView1.getFirstVisibleItemIndex - first visible ItemIndex ListView1.getVisibleCount - amount of visible items ListView1.getLastVisibleItemindex - first visible ItemIndex + amount of visible items ListView1.SeparatorLeftOffset - indent for separator line ListView1.SeparatorRightOffset - indent for separator line ListView1.EnableTouchAnimation - enable/disable touch animation
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值