ã¯ããã«
iOS/Android ã§ãŠãŒã¶ãŒã®æ å ±ãã»ãã¥ã¢ã«æ±ãå¿ èŠããã£ãã®ã§ã調æ»ãããšãã Android ã«ã¯ EncryptedSharedPreferences ãååšããããšãç¥ããŸãããiOS ã«ã¯ Keychain Services ãååšããŸãã
ä»å㯠Unity ã® iOS/Android ãã©ãããã©ãŒã äžã§èšå®å€ãä¿åããããã®å®è£ ãè¡ãå¿ èŠããã£ãã®ã§ãUnity ããæ±ãããããã€ãã£ããã©ã°ã€ã³ãäœæããŸãããä»åŸããããã£ãèŠæã¯ããããã§ããã®ã§ãèšäºãšããŠæé ãå 容ãæžãèšããŠããããšã«ããŸããã
æ¬èšäºå ã§çŽ¹ä»ããŠããã³ãŒãã¯äžèšã«ã¢ããæžã¿ã§ãã
https://github.com/nikaera/Unity-iOS-Android-SecretManager-Sample
åäœç°å¢
- MacBook Air (M1, 2020)
- Unity 2020.3.15f2
- Android 6.0 以äž
- EncryptedSharedPreferences ã䜿çšå¯èœãªããŒãžã§ã³
Android ã®ãã€ãã£ããã©ã°ã€ã³ãäœæãã
Android ç°å¢ã§ã¯ãŸã External Dependency Manager for Unity ãå©çšããŠãUnity ã® Android ãã€ãã£ããã©ã°ã€ã³ã§ EncryptedSharedPreferences
å©çšå¯èœã«ããŸãã
(è¿œèš) Gradle ãå©çšããã©ã€ãã©ãªã®ã€ã³ã¹ããŒã«æ¹æ³
shiena ããã«ãææããã ããã®ã§ããããã¡ãã®èšäºã®ããã« Gradle ãå©çšããããšã§ãç°¡æã«ã©ã€ãã©ãªã®åã蟌ã¿ãå¯èœãªããã§ããã
æé ã¯äžèšã®èšäºããåç
§ããã ããšããŠãGradle ãå©çšããæ¹æ³ã§å€éšã©ã€ãã©ãªãåã蟌ãéã® Assets/Plugins/Android/mainTemplate.gradle
ããã³ Assets/Plugins/Android/gradleTemplate.properties
ã¯äžèšã«ãªããŸãã
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation 'androidx.security:security-crypto:1.1.0-alpha03'
**DEPS**}
android {
org.gradle.jvmargs=-Xmx**JVM_HEAP_SIZE**M
org.gradle.parallel=true
android.enableR8=**MINIFY_WITH_R_EIGHT**
+ android.useAndroidX=true
unityStreamingAssets=.unity3d**STREAMING_ASSETS**
**ADDITIONAL_PROPERTIES**
Gradle ãå©çšããæ¹æ³ã§ã©ã€ãã©ãªãå©çšãããéã¯ã次㮠External Dependency Manager for Unity ã§å¿
èŠãªããã±ãŒãžãã€ã³ã¹ããŒã«ãã
ã®æé ã¯ã¹ãããå¯èœã§ããEncryptedSharedPreferences ãå©çšããããã®ãã€ãã£ãã³ãŒããè¿œå ãã
ã®ã¹ãããããé²ããŠãã ããã
External Dependency Manager for Unity
ãå©çšããæ¹æ³ã ãšãåã蟌ã¿å
ãããžã§ã¯ãå
ã§ã©ã€ãã©ãªã®ç«¶åãçºçããæãããããŸããGradle ãå©çšããæ¹æ³ã§ããã°åé¿ãå¯èœã§ãã1
External Dependency Manager for Unity ã§å¿ èŠãªããã±ãŒãžãã€ã³ã¹ããŒã«ãã
External Dependency Manager for Unity
ãã€ã³ããŒããããã unitypackage ãããŠã³ããŒãããŠãEncryptedSharedPreferences
ãå°å
¥ããã Unity ãããžã§ã¯ããéããŠãã unitypackage
ãã¯ãªãã¯ããããšã§ãExternal Dependency Manager for Unity
ã Unity ãããžã§ã¯ãã«ã€ã³ããŒãããŸãã
Unity ãããžã§ã¯ãã® Build Settings
ãããã©ãããã©ãŒã 㯠Android ã«åãæ¿ããŠãããŸããEnable Android Auto-resolution?
ãšãããã€ã¢ãã°ã®éžæè¢ã¯ã©ã¡ããéžãã§ãæ§ããŸããã2
External Dependency Manager for Unity ã§åçš®ããã±ãŒãžã管çããæ¹æ³ã¯ README ã«èšèŒãããéãã*Dependencies.xml
ãšãããã¡ã€ã«ã Editor
ãã©ã«ãã«é
眮ããããšã§å¯èœã«ãªããŸãã
ä»å㯠EncryptedSharedPreferences
ãå°å
¥ãããããäžèšã® xml ãã¡ã€ã«ã Editor
ãã©ã«ãå
ã«é
眮ããŸãã
<?xml version="1.0" encoding="utf-8"?>
<dependencies>
<androidPackages>
<!--
æ¬èšäºã§ã¯ããŒãžã§ã³ 1.1.0-alpha03 ãå©çšããŠãã
-->
<androidPackage spec="androidx.security:security-crypto:1.1.0-alpha03">
<androidSdkPackageIds>
<!--
Google ã® Maven ãªããžããªããã€ã³ã¹ããŒã«ããããã
extra-google-m2repository ãæå®ãã
-->
<androidSdkPackageId>extra-google-m2repository</androidSdkPackageId>
</androidSdkPackageIds>
</androidPackage>
</androidPackages>
</dependencies>
ãã®åŸãUnity ã¡ãã¥ãŒãã Assets -> External Dependency Manager -> Android Resolver -> Force Resolve
ãéžæããŠãAssets/Editor/AndroidPluginDependencies.xml
ã®å
容ãå
ã« EncryptedSharedPreferences
ãå©çšããã®ã«å¿
èŠãªããã±ãŒãžãèªå㧠Assets/Plugins/Android
ãã©ã«ãã«ããŠã³ããŒãããŸãã
1. Unity ã¡ãã¥ãŒãã Assets -> External Dependency Manager -> Android Resolver -> Force Resolve
ãéžæãã
2. å®è¡ã«æåãããš EncryptedSharedPreferences ãå©çšããã®ã«å¿
èŠãªã©ã€ãã©ãªçŸ€ã Assets/Plugins/Android
ãã©ã«ãã«é
眮ããã
ãããŸã§æ¥ãã°ããšã¯ Android ãã€ãã£ãã³ãŒãã Assets/Plugins/Android
ãã©ã«ãå
ã«é
眮ã㊠Unity åŽããå©ããããã«ããã ãã§ãã
EncryptedSharedPreferences ãå©çšããããã®ãã€ãã£ãã³ãŒããè¿œå ãã
æ©éäžèšã® Android ãã€ãã£ãã³ãŒãã Assets/Plugins/Android/SecretManager.java
ã«é
眮ããŸãã
package com.nikaera;
import com.unity3d.player.UnityPlayerActivity;
import java.lang.Exception;
// External Dependency Manager for Unity ã«ãã£ãŠã
// å¿
èŠãª jar ãå«ãŸããŠãããã EncryptedSharedPreferences ã®å©çšãå¯èœã«ãªã
import androidx.security.crypto.EncryptedSharedPreferences;
import androidx.security.crypto.MasterKey;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.util.Log;
public class SecretManager {
private SharedPreferences sharedPreferences;
public SecretManager(Context context) {
try {
// EncryptedSharedPreferences ã§èšå®å€ãä¿åããéã«çšããã
// æå·éµãæ±ãããã®ã©ãããŒã¯ã©ã¹ãããã©ã«ãèšå®ã§äœæãã
MasterKey masterKey = new MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build();
// EncryptedSharedPreferences ã®ã€ã³ã¹ã¿ã³ã¹ãçæãã
// ã³ã³ã¹ãã©ã¯ã¿ã§äœæãã masterKey ãæå®ããŠãã
this.sharedPreferences = EncryptedSharedPreferences.create(
context, context.getPackageName(), masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* æå®ããããŒã§å€ãä¿åããé¢æ°
* @param key å€ãä¿åããéã«çšããããŒ
* @param value ä¿åãããå€
* @return boolean å€ã®ä¿åã«æåãããã©ãã
*/
public boolean put(String key, String value) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(key, value);
return editor.commit();
}
/**
* æå®ããããŒã§ä¿åããå€ãååŸããé¢æ°
* `put` é¢æ°ã§ä¿åããå€ãååŸããã®ã«å©çšãã
* @param key ååŸãããå€ã®ããŒ
* @return string ããŒã«çŽã¥ãå€ãååšããªããã°ç©ºæåãè¿åŽããã
*/
public String get(String key) {
return sharedPreferences.getString(key, null);
}
/**
* æå®ããããŒã§å€ãåé€ããé¢æ°
* @param key åé€ãããå€ã®ããŒ
* @return boolean å€ã®åé€ã«æåãããã©ãã
*/
public boolean delete(String key) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.remove(key);
return editor.commit();
}
}
ãã®åŸãäžèšã Unity ã¹ã¯ãªããããå®è¡å¯èœã«ããããã® C# ã¯ã©ã¹ãäœæããŸããæ¬èšäºã§ã¯ãã¡ã€ã«ã Assets/Scripts/EncryptedSharedPreferences.cs
ã«é
眮ããŸãã
using UnityEngine;
/// <summary>
/// å©çšãããã€ãã£ãã³ãŒã㯠<c>Assets/Plugins/Android/SecretManager.java</c> ã«èšèŒ
/// </summary>
/// <remarks>
/// <a href="https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences">EncryptedSharedPreferences</a>
/// </remarks>
class EncryptedSharedPreferences
{
private readonly AndroidJavaObject _secretManager;
public EncryptedSharedPreferences()
{
// ã³ã³ã¹ãã©ã¯ã¿ã§ com.nikaera.SecretManager ã®ã€ã³ã¹ã¿ã³ã¹çæãè¡ã
var activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer")
.GetStatic<AndroidJavaObject>("currentActivity");
var context = activity.Call<AndroidJavaObject>("getApplicationContext");
_secretManager = new AndroidJavaObject("com.nikaera.SecretManager", context);
}
public bool Put(string key, string value)
{
return _secretManager.Call<bool>("put", key, value);
}
public string Get(string key)
{
return _secretManager.Call<string>("get", key);
}
public bool Delete(string key)
{
return _secretManager.Call<bool>("delete", key);
}
}
ããšã¯çšéã«å¿ããŠäžèšã®ãããªã³ãŒãã§èšå®å€ã®ä¿åãååŸãªã©ãè¡ããŸãã
// ...
var _sharedPreferences = new EncryptedSharedPreferences();
// name ãããŒãšããŠå€ã nikaera ã§ä¿åãã
_sharedPreferences.Put("name", "nikaera");
// name ãããŒãšããŠå€ãååŸãã
var name = _sharedPreferences.Get("name");
// "nikaera" ãåºåããã
Debug.Log(name);
//ãname ãããŒãšããŠå€ãåé€ãã
_sharedPreferences.Delete("name");
// ...
iOS ã®ãã€ãã£ããã©ã°ã€ã³ãäœæãã
iOS ã®å Žåã¯å€éšã©ã€ãã©ãªãå©çšããªããããExternal Dependency Manager for Unity
ã¯å©çšããŸãããæ¬æ¥ã§ããã° Swift ã§ä¿¡é Œã§ããå€éšãã¬ãŒã ã¯ãŒã¯ãåã蟌ã¿å©çšã§ãããšè¯ãããã§ãããä»å㯠Objective-C ã§ãã€ãã£ããã©ã°ã€ã³ãæžããŠãããŸãã3
Keychain Services ãå©çšããããã®ãã€ãã£ãã³ãŒããè¿œå ãã
æ©éäžèšã® iOS ãã€ãã£ãã³ãŒãã Assets/Plugins/iOS/KeychainService.mm
ã«é
眮ããŸãã
// Keychain Services ãå©çšããããã« Security ãã¬ãŒã ã¯ãŒã¯ãå©çšãã
#import <Security/Security.h>
extern "C"
{
// æå®ããããŒã§å€ãä¿åããé¢æ°
// - param
// - dataType: å€ãä¿åããéã«çšããããŒ
// - value: ä¿åãããå€
// - return
// - ä¿åæã®ã¹ããŒã¿ã¹ã³ãŒããè¿åŽãã (0 以å€ã¯å€±æ)
int addItem(const char *dataType, const char *value)
{
NSMutableDictionary* attributes = nil;
NSMutableDictionary* query = [NSMutableDictionary dictionary];
NSData* sata = [[NSString stringWithCString:value encoding:NSUTF8StringEncoding] dataUsingEncoding:NSUTF8StringEncoding];
[query setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
[query setObject:(id)[NSString stringWithCString:dataType encoding:NSUTF8StringEncoding] forKey:(id)kSecAttrAccount];
OSStatus err = SecItemCopyMatching((CFDictionaryRef)query, NULL);
if (err == noErr) {
attributes = [NSMutableDictionary dictionary];
[attributes setObject:sata forKey:(id)kSecValueData];
[attributes setObject:[NSDate date] forKey:(id)kSecAttrModificationDate];
err = SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attributes);
return (int)err;
} else if (err == errSecItemNotFound) {
attributes = [NSMutableDictionary dictionary];
[attributes setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
[attributes setObject:(id)[NSString stringWithCString:dataType encoding:NSUTF8StringEncoding] forKey:(id)kSecAttrAccount];
[attributes setObject:sata forKey:(id)kSecValueData];
[attributes setObject:[NSDate date] forKey:(id)kSecAttrCreationDate];
[attributes setObject:[NSDate date] forKey:(id)kSecAttrModificationDate];
err = SecItemAdd((CFDictionaryRef)attributes, NULL);
return (int)err;
} else {
return (int)err;
}
}
// æå®ããããŒã§å€ãååŸããé¢æ°
// - param
// - dataType: å€ãååŸããéã«çšããããŒ
// - return
// - ããŒã«çŽã¥ãå€ãååšããªããã°ç©ºæåãè¿åŽããã
char* getItem(const char *dataType)
{
NSMutableDictionary* query = [NSMutableDictionary dictionary];
[query setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
[query setObject:(id)[NSString stringWithCString:dataType encoding:NSUTF8StringEncoding] forKey:(id)kSecAttrAccount];
[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
CFDataRef cfresult = NULL;
OSStatus err = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef*)&cfresult);
if (err == noErr) {
NSData* passwordData = (__bridge_transfer NSData *)cfresult;
const char* value = [[[NSString alloc] initWithData:passwordData encoding:NSUTF8StringEncoding] UTF8String];
char *str = strdup(value);
return str;
} else {
return NULL;
}
}
// æå®ããããŒã§å€ãåé€ããé¢æ°
// - param
// - dataType: å€ãåé€ããéã«çšããããŒ
// - return
// - ä¿åæã®ã¹ããŒã¿ã¹ã³ãŒããè¿åŽãã (0 以å€ã¯å€±æ)
int deleteItem(const char *dataType)
{
NSMutableDictionary* query = [NSMutableDictionary dictionary];
[query setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
[query setObject:(id)[NSString stringWithCString:dataType encoding:NSUTF8StringEncoding] forKey:(id)kSecAttrAccount];
OSStatus err = SecItemDelete((CFDictionaryRef)query);
if (err == noErr) {
return 0;
} else {
return (int)err;
}
}
}
Keychain Services
㯠Security
ãã¬ãŒã ã¯ãŒã¯ãå©çšãããããKeychainService.mm
ã«å¯Ÿã㊠Security
ãã¬ãŒã ã¯ãŒã¯ã®äŸåé¢ä¿ãèšå®ããå¿
èŠããããŸãã
KeychainService.mm
㧠Security
ãã¬ãŒã ã¯ãŒã¯ã®å©çšãå¯èœã«ãã
ãã®åŸãäžèšã Unity ã¹ã¯ãªããããå®è¡å¯èœã«ããããã® C# ã¯ã©ã¹ãäœæããŸããæ¬èšäºã§ã¯ãã¡ã€ã«ã Assets/Scripts/KeychainService.cs
ã«é
眮ããŸãã
using System.Runtime.InteropServices;
/// <summary>
/// å®è£
㯠<c>Assets/Plugins/iOS/KeychainService.mm</c> ã«èšèŒ
/// </summary>
/// <remarks>
/// <a href="https://developer.apple.com/documentation/security/keychain_services">Keychain Services</a>
/// </remarks>
class KeychainService
{
#if UNITY_IOS
[DllImport("__Internal")]
private static extern int addItem(string dataType, string value);
[DllImport("__Internal")]
private static extern string getItem(string dataType);
[DllImport("__Internal")]
private static extern int deleteItem(string dataType);
#endif
public bool Put(string key, string value)
{
#if UNITY_IOS
// è¿åŽãããã¹ããŒã¿ã¹ã 0 ãªãæå
return addItem(key, value) == 0;
#endif
}
public string Get(string key)
{
#if UNITY_IOS
return getItem(key);
#else
return null;
#endif
}
public bool Delete(string key)
{
#if UNITY_IOS
// è¿åŽãããã¹ããŒã¿ã¹ã 0 ãªãæå
return deleteItem(key) == 0;
#endif
}
}
ããšã¯çšéã«å¿ããŠäžèšã®ãããªã³ãŒãã§èšå®å€ã®ä¿åãååŸãªã©ãè¡ããŸãã
// ...
var _keychainService = new KeychainService();
// name ãããŒãšããŠå€ã nikaera ã§ä¿åãã
_keychainService.Put("name", "nikaera");
// name ãããŒãšããŠå€ãååŸãã
var name = _keychainService.Get("name");
// "nikaera" ãåºåããã
Debug.Log(name);
//ãname ãããŒãšããŠå€ãåé€ãã
_keychainService.Delete("name");
// ...
(äœè«) ã€ã³ã¿ãŒãã§ãŒã¹ã§ iOS/Android ã®ãµããŸããå ±éåãã
ãã®ãŸãŸã ãšãã©ãããã©ãŒã ãåãæ¿ããæ¯ã«ã³ãŒããæžãçŽããªããšãªããªãã®ã§ãã€ã³ã¿ãŒãã§ãŒã¹ãå©çšããŠå ±éåãè¡ããŸãã
public interface ISecretManager
{
/// <summary>
/// æå®ããããŒã§å€ãä¿åããé¢æ°
/// </summary>
/// <param name="key">ããŒ</param>
/// <param name="value">å€</param>
/// <returns>ä¿åã«æåãããã©ãã</returns>
bool Put(string key, string value);
/// <summary>
/// æå®ããããŒã®å€ãååŸããé¢æ°
/// </summary>
/// <param name="key">ããŒ</param>
/// <returns>æå®ããããŒã§èšå®ãããå€ãç¡ããã° null</returns>
string Get(string key);
/// <summary>
/// æå®ããããŒã®å€ãåé€ããé¢æ°
/// </summary>
/// <param name="key">ããŒ</param>
/// <returns>åé€ã«æåãããã©ãã</returns>
bool Delete(string key);
}
ãã®åŸãAssets/Scripts/EncryptedSharedPreferences.cs
ããã³ Assets/Scripts/KeychainService.cs
ãäžèšã®éã ISecretManager
ã®å®è£
ã«çŽä»ããŸãã
using UnityEngine;
/// <summary>
/// å©çšãããã€ãã£ãã³ãŒã㯠<c>Assets/Plugins/Android/SecretManager.java</c> ã«èšèŒ
/// </summary>
/// <remarks>
/// <a href="https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences">EncryptedSharedPreferences</a>
/// </remarks>
class EncryptedSharedPreferences: ISecretManager
{
private readonly AndroidJavaObject _secretManager;
public EncryptedSharedPreferences()
{
var activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer")
.GetStatic<AndroidJavaObject>("currentActivity");
var context = activity.Call<AndroidJavaObject>("getApplicationContext");
_secretManager = new AndroidJavaObject("com.nikaera.SecretManager", context);
}
#region ISecretManager
public bool Put(string key, string value)
{
return _secretManager.Call<bool>("put", key, value);
}
public string Get(string key)
{
return _secretManager.Call<string>("get", key);
}
public bool Delete(string key)
{
return _secretManager.Call<bool>("delete", key);
}
#endregion
}
using System.Runtime.InteropServices;
/// <summary>
/// å®è£
㯠<c>Assets/Plugins/iOS/KeychainService.mm</c> ã«èšèŒ
/// </summary>
/// <remarks>
/// <a href="https://developer.apple.com/documentation/security/keychain_services">Keychain Services</a>
/// </remarks>
class KeychainService: ISecretManager
{
#if UNITY_IOS
[DllImport("__Internal")]
private static extern int addItem(string dataType, string value);
[DllImport("__Internal")]
private static extern string getItem(string dataType);
[DllImport("__Internal")]
private static extern int deleteItem(string dataType);
#endif
// KeychainService.mm ã«å®çŸ©ããé¢æ°ãåŒã³åºã
#region ISecretManager
public bool Put(string key, string value)
{
#if UNITY_IOS
return addItem(key, value) == 0;
#else
return false;
#endif
}
public string Get(string key)
{
#if UNITY_IOS
return getItem(key);
#else
return null;
#endif
}
public bool Delete(string key)
{
#if UNITY_IOS
return deleteItem(key) == 0;
#else
return false;
#endif
}
#endregion
}
ããšã¯äžèšããããªã«å©çšå¯èœãª SecretManager
ã¯ã©ã¹ãäœæããŸãã
using UnityEngine;
/// <summary>
/// <em>Editor å©çšæã®ã¿ PlayerPrefs ãå©çšãã</em>
/// </summary>
/// <remarks><see cref="KeychainService" />, <see cref="EncryptedSharedPreferences" /></remarks>
public static class SecretManager
{
#if UNITY_EDITOR
#elif UNITY_ANDROID
private static ISecretManager _instance = new EncryptedSharedPreferences();
#elif UNITY_IOS
private static ISecretManager _instance = new KeychainService();
#endif
public static bool Put(string key, string value)
{
#if UNITY_EDITOR
PlayerPrefs.SetString(key, value);
PlayerPrefs.Save();
return true;
#elif UNITY_IOS || UNITY_ANDROID
return _instance.Put(key, value);
#else
Debug.Log("Not Implemented.");
return false;
#endif
}
public static string Get(string key)
{
#if UNITY_EDITOR
return PlayerPrefs.GetString(key);
#elif UNITY_IOS || UNITY_ANDROID
return _instance.Get(key);
#else
Debug.Log("Not Implemented.");
return null;
#endif
}
public static bool Delete(string key)
{
#if UNITY_EDITOR
PlayerPrefs.DeleteKey(key);
PlayerPrefs.Save();
return true;
#elif UNITY_IOS || UNITY_ANDROID
return _instance.Delete(key);
#else
Debug.Log("Not Implemented.");
return false;
#endif
}
}
ããã§ãã©ãããã©ãŒã éã®å®è£
å·®ç°ãæ°ã«ããããšãªããäžèšã®ãããªèšè¿°ã§èšå®å€ã®ä¿åãååŸãªã©ãè¡ããŸããiOS/Android 以å€ã®ãã©ãããã©ãŒã ã§è¿œå å®è£
ãããå Žå㯠ãã©ãããã©ãŒã äŸåã³ã³ãã€ã« ãš ISecretManager
ã®å®è£
ã¯ã©ã¹ãæ°ãã«äœæããããšã§ç°¡åã«è¿œå ã§ããŸãã
// ...
// name ãããŒãšããŠå€ã nikaera ã§ä¿åãã
SecretManager.Put("name", "nikaera");
// name ãããŒãšããŠå€ãååŸãã
var name = SecretManager.Get("name");
// "nikaera" ãåºåããã
Debug.Log(name);
//ãname ãããŒãšããŠå€ãåé€ãã
SecretManager.Delete("name");
// ...
ãããã«
ä»å㯠iOS/Android ã§èšå®å€ãã»ãã¥ã¢ã«æ±ãããã®æ¹æ³ã«ã€ããŠãŸãšããŠã¿ãŸãããå®é㯠Keychain Services
åšãã¯å®è£
ã倧å€ãªã®ã§ãExternal Dependency Manager for Unity
ãšã䜿ã£ãŠ KeychainAccess ã®ãããªå€éšã©ã€ãã©ãªãå©çšããæ§æã®ã»ããè¯ããšæãããŸãã
æ¬èšäºã®å 容ã«èª€ãããã£ãããå®éã«ã¯ã»ãã¥ã¢ãªå®è£ ãã§ããŠããªãçã ããã°æ¯éã³ã¡ã³ãã§ãææããã ããŸããšå¹žãã§ãã
åèãªã³ã¯
- Android ããããã㌠ | Android Developers
- EncryptedSharedPreferences  | Android ããããã㌠ | Android Developers
- Keychain Services | Apple Developer Documentation
- SharedPreferences ãèªåã§é£èªåããã®ã¯ããå€ã?ãããã㯠EncryptedSharedPrefenreces ã䜿ãã - Qiita
- iOS ã®ããŒãã§ãŒã³ã«ã€ã㊠- Qiita
- Unity 㧠IOS ã«ã»ãã¥ã¢ã«å€ãä¿åããã«ã¯ KeyChain ã䜿ãã - Qiita
- googlesamples/unity-jar-resolver: Unity plugin which resolves Android & iOS dependencies and performs version management
éã«
External Dependency Manager for Unity
ãå©çšããæ¹æ³ã®ã¡ãªããã¯ãUnityPackage ãªã©ã§ã©ã€ãã©ãªãšããŠé åžããéã«ãã©ã€ãã©ãªãåäœãããã®ã«å¿ èŠãªå€éšããã±ãŒãžãå梱ããç¶æ ã§é åžãå¯èœã«ãªããªã©ããããŸãã(åœç¶ã©ã€ã»ã³ã¹ã«ã¯æ°ãä»ããå¿ èŠããããŸãã…) ↩︎ããã±ãŒãžã®äŸåé¢ä¿ãèªåã§è§£æ±ºãããã©ãããšããéžæè¢ã«ãªããŸããæ¬èšäºã§ã¯æ瀺çã« Resolve ãå®è¡ãããã
Disable
ã§ãEnable
ã§ãé²è¡äžã®åé¡ã¯ãããŸããã ↩︎CocoaPods ããµããŒããããŠãããããªã®ã§ãiOS ã§ã Android åæ§ãå€éšã©ã€ãã©ãªãåã蟌ãã®ã¯ç°¡åã«ã§ãããã§ãããäŸãã° KeychainAccess ãšã䜿ãããã ↩︎