【Unity】iOSでウィンドウからSafeAreaを取得するプラグインを作る
iOS 15でデバイスを回転させるとScreen.safeAreaが正しい値を返さないことがフォーラムで話題になっています。
Unity SafeArea is inconsistent between different starting rotations
Screen.safeAreaが正しい値を返さないのは何年も前からある現象で、UnityとしてはもうFixしたと言ってみたり、また再発したりを繰り返しています。
原因はUIViewのsafeAreaInsetsが正しい値を返さないことにあり、UIWindowのsafeAreaInsetsだと正しかったりします。
どうもウィンドウからビューにイベントの伝達がうまくいってないっぽく、これはUnityの責任というより、Appleの責任ではないかとも思われます。
UnityでiOSビルドしたプロジェクトを探すと、UnityView.mmというファイルのComputeSafeArea(UIView* view)という関数でsafeAreaを取得しているようですが、毎回ここを書き換えるのも面倒です。
なのでフォーラムの投稿にもありますが、UIWindowからsafeAreaを取得するネイティブプラグインを作って対処することを考えます。
iOSプラグイン
extern "C"
{
char* convertNSStringToCString(const NSString* nsString);
char* GetWindowSafeArea();
}
char* convertNSStringToCString(const NSString* nsString)
{
if (nsString == NULL)
return NULL;
const char* nsStringUtf8 = [nsString UTF8String];
char* cString = (char*)malloc(strlen(nsStringUtf8) + 1);
strcpy(cString, nsStringUtf8);
return cString;
}
char* GetWindowSafeArea()
{
UIEdgeInsets insets = UIEdgeInsetsZero;
UIWindow *window = UnityGetMainWindow();
CGRect bounds = window.bounds;
CGFloat scale = window.screen.scale;
if (@available(iOS 11.0, *)) {
insets = window.safeAreaInsets;
}
// 上下逆の座標系
CGFloat x = insets.left * scale;
CGFloat y = insets.bottom * scale;
CGFloat w = (bounds.size.width - insets.left - insets.right) * scale;
CGFloat h = (bounds.size.height - insets.top - insets.bottom) * scale;
CGRect safeArea = CGRectMake(x, y, w, h);
NSString *stringData = [NSString stringWithFormat:@"%f/%f/%f/%f", safeArea.origin.x, safeArea.origin.y, safeArea.size.width, safeArea.size.height];
char* data = convertNSStringToCString(stringData);
return data;
}
Unity側の読み込み
using UnityEngine;
using System.Runtime.InteropServices;
public class UtilityPlugin : MonoBehaviour
{
#if UNITY_EDITOR
#elif UNITY_IPHONE
[DllImport("__Internal")]
private static extern string GetWindowSafeArea();
#elif UNITY_ANDROID
#else
#endif
public static Rect GetSafeArea()
{
Rect rect = Screen.safeArea;
#if UNITY_EDITOR
#elif UNITY_IPHONE
string data = GetWindowSafeArea();
if (data != null)
{
string[] rectArray = data.Split('/');
if (rectArray.Length >= 4)
{
float x = float.Parse(rectArray[0]);
float y = float.Parse(rectArray[1]);
float w = float.Parse(rectArray[2]);
float h = float.Parse(rectArray[3]);
rect = new Rect(x, y, w, h);
}
}
#elif UNITY_ANDROID
#endif
return rect;
}
}
extern "C"
{
char* convertNSStringToCString(const NSString* nsString);
char* GetWindowSafeArea();
}
char* convertNSStringToCString(const NSString* nsString)
{
if (nsString == NULL)
return NULL;
const char* nsStringUtf8 = [nsString UTF8String];
char* cString = (char*)malloc(strlen(nsStringUtf8) + 1);
strcpy(cString, nsStringUtf8);
return cString;
}
char* GetWindowSafeArea()
{
UIEdgeInsets insets = UIEdgeInsetsZero;
UIWindow *window = UnityGetMainWindow();
CGRect bounds = window.bounds;
CGFloat scale = window.screen.scale;
if (@available(iOS 11.0, *)) {
insets = window.safeAreaInsets;
}
// 上下逆の座標系
CGFloat x = insets.left * scale;
CGFloat y = insets.bottom * scale;
CGFloat w = (bounds.size.width - insets.left - insets.right) * scale;
CGFloat h = (bounds.size.height - insets.top - insets.bottom) * scale;
CGRect safeArea = CGRectMake(x, y, w, h);
NSString *stringData = [NSString stringWithFormat:@"%f/%f/%f/%f", safeArea.origin.x, safeArea.origin.y, safeArea.size.width, safeArea.size.height];
char* data = convertNSStringToCString(stringData);
return data;
}
using UnityEngine;
using System.Runtime.InteropServices;
public class UtilityPlugin : MonoBehaviour
{
#if UNITY_EDITOR
#elif UNITY_IPHONE
[DllImport("__Internal")]
private static extern string GetWindowSafeArea();
#elif UNITY_ANDROID
#else
#endif
public static Rect GetSafeArea()
{
Rect rect = Screen.safeArea;
#if UNITY_EDITOR
#elif UNITY_IPHONE
string data = GetWindowSafeArea();
if (data != null)
{
string[] rectArray = data.Split('/');
if (rectArray.Length >= 4)
{
float x = float.Parse(rectArray[0]);
float y = float.Parse(rectArray[1]);
float w = float.Parse(rectArray[2]);
float h = float.Parse(rectArray[3]);
rect = new Rect(x, y, w, h);
}
}
#elif UNITY_ANDROID
#endif
return rect;
}
}
Author And Source
この問題について(【Unity】iOSでウィンドウからSafeAreaを取得するプラグインを作る), 我々は、より多くの情報をここで見つけました https://qiita.com/ichiromatano/items/943f54509000b8e9c959著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .