iOS 10 버전 부터, Apple은 앱 개발자에게 사용하는 프레임웍에 대한 설명을 info.plist 파일에 기술하도록 요청하고 있습니다. 이 설명은 사용자에게 해당 기능 사용에 대한 허가를 요청할때 보여지게 됩니다(e.g. location, accelerometer, etc.). 이 요구사항은 탭조이 같은 써드파티 SDK까지 확대 되었습니다. 탭조이는 편의를 위해 탭조이가 사용하고 있는 프레임웍에 대해서 info.plist에 포함해야할 내용을 다음과 같이 제공해 드립니다.
Function
Key
Suggested Text
Accessing media library
NSAppleMusicUsageDescription
광고 경험 향상을 위해서 미디어 라이브러리가 사용됩니다.
Accessing location data all time*
NSLocationAlwaysUsageDescription
광고 경험 향상을 위해서 위치 정보에 접근할 수 있습니다.
Accessing location data when the app is in use*
NSLocationWhenInUseUsageDescription
광고 경험 향상을 위해서 위치 정보에 접근할 수 있습니다.
Accessing accelerometer
NSMotionUsageDescription
광고 경험 향상을 위해서 가속센서를 사용할 수 있습니다.
Accessing photo library
NSPhotoLibraryUsageDescription
개인화된 광고 경험 향상을 위해서 사진 정보에 접근할 수 있습니다.
* SDK 11.9.0부터 CoreLocation.framework 은 optional 입니다.
만일 위와 같은 정보를 info.plist에 추가하지 않으면 다음과 같은 사유로 앱스토어 등록이 거부될 수 있습니다.
This app attempts to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSAppleMusicUsageDescription key with a string value explaining to the user how the app uses this data.
This app attempts to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSLocationAlwaysUsageDescription key with a string value explaining to the user how the app uses this data.
This app attempts to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSLocationWhenInUseDescription key with a string value explaining to the user how the app uses this data.
This app attempts to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSMotionUsageDescription key with a string value explaining to the user how the app uses this data.
This app attempts to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSPhotoLibraryUsageDescription key with a string value explaining to the user how the app uses this data.
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TimeServer : MonoBehaviour {
[SerializeField]
private string _comment = "만료시킬 날짜를 적으세요 (한국시각 기준)";
public int _yyyy, _mm, _dd;
private DateTime _expireDateTime, _nowServerDateTime, _nowLocalDateTime;
private TimeSpan _duration;
// Use this for initialization
void Start () {
// 한국 시각
_duration = System.TimeSpan.FromHours(9);
_expireDateTime = new DateTime(Mathf.Clamp(_yyyy, 1900, 3000), Mathf.Clamp(_mm, 1,12), Mathf.Clamp(_dd, 1, 31));
_nowLocalDateTime = DateTime.Now;
_nowServerDateTime = GetNISTDate().Add(_duration);
if (Debug.isDebugBuild)
{
Debug.LogWarning("만료지정일 : " + _expireDateTime);
Debug.LogWarning("현재 로컬 시각 :" + _nowLocalDateTime);
Debug.LogWarning("현재 서버 시각 :" + _nowServerDateTime);
}
if (_nowLocalDateTime < _expireDateTime)
{
if (_nowServerDateTime < _expireDateTime)
{
// Debug.Log("실행");
}
else
{
// Debug.Log("서버 체크 결과 만료 됨");
}
}
else
{
// Debug.Log("로컬 체크 결과 만료 됨");
}
}
#region NTPTIME
//NTP time 을 NIST 에서 가져오기
// 4초 이내에 한번 이상 요청 하면, ip가 차단됩니다.
public static DateTime GetDummyDate()
{
return new DateTime(2017, 12, 24); //to check if we have an online date or not.
}
public static DateTime GetNISTDate()
{
System.Random ran = new System.Random(DateTime.Now.Millisecond);
DateTime date = GetDummyDate();
string serverResponse = string.Empty;
// NIST 서버 목록
string[] servers = new string[] {
"time.bora.net",
//"time.nuri.net",
//"ntp.kornet.net",
//"time.kriss.re.kr",
//"time.nist.gov",
//"maths.kaist.ac.kr",
"nist1-ny.ustiming.org",
"time-a.nist.gov",
"nist1-chi.ustiming.org",
"time.nist.gov",
"ntp-nist.ldsbc.edu",
"nist1-la.ustiming.org"
};
// 너무 많은 요청으로 인한 차단을 피하기 위해 한 서버씩 순환한다. 5번만 시도한다.
for (int i = 0; i < 5; i++)
{
try
{
// StreamReader(무작위 서버)
StreamReader reader = new StreamReader(new System.Net.Sockets.TcpClient(servers[ran.Next(0, servers.Length)], 13).GetStream());
serverResponse = reader.ReadToEnd();
reader.Close();
// 서버 리스폰스를 표시한다. (디버그 확인용)
if (Debug.isDebugBuild)
Debug.Log(serverResponse);
// 시그니처가 있는지 확인한다.
if (serverResponse.Length > 47 && serverResponse.Substring(38, 9).Equals("UTC(NIST)"))
{
// 날짜 파싱
int jd = int.Parse(serverResponse.Substring(1, 5));
int yr = int.Parse(serverResponse.Substring(7, 2));
int mo = int.Parse(serverResponse.Substring(10, 2));
int dy = int.Parse(serverResponse.Substring(13, 2));
int hr = int.Parse(serverResponse.Substring(16, 2));
int mm = int.Parse(serverResponse.Substring(19, 2));
int sc = int.Parse(serverResponse.Substring(22, 2));
if (jd > 51544)
yr += 2000;
else
yr += 1999;
date = new DateTime(yr, mo, dy, hr, mm, sc);
// Exit the loop
break;
}
}
catch (Exception e)
{
/* 아무것도 하지 않고 다음 서버를 시도한다. */
}
}
return date;
}
#endregion
}