Xcode15.3でビルドしたUnityアプリをiOS17で実行した際に%が二重にURLエンコードされる件とサーバ側回避策
概要
- Xcode15.3でビルドしたUnityアプリをiOS17で実行した際に%が二重にURLエンコードされる問題があった
- サーバ(Rails)側で回避策を講じた
環境
- Unity2021.3.29f1
- Xcode15.3
発生した現象
運用中のUnityアプリで、Xcodeを15.3にバージョンアップしたビルドで動作確認をしていたところ、iOS17のみサーバ(Rails)の特定APIアクセス時にサーバ側アプリケーションエラーが発生するようになりました。
iOS16以下、Androidでは従来通り問題なし。
調査経緯
サーバ側の行動ログから、当該リクエストのURLのクエリを確認すると、差異がありました。
# これまでの問題ないパターン
...&trade_tabs=[2,%204]
# 当該OS当該verのパターン
...&trade_tabs=%5B2,%25204%5D
どうも従来はエンコード1回だったのが、問題のケースでは[2, 4] → [2,%204] → %5B2,%25204%5D
と2回エンコードが行われているっぽい
というところでios 17 percent encoding unity
で検索してみたところ、ヒット
- Bug - NSURL percentage is double-encoded in iOS 17 - Unity Forum
- URL Encoding doesn't work with iOS 17 which is working with iOS 16 | Apple Developer Forums
- URLWithString: | Apple Developer Documentation
For apps linked on or after iOS 17 and aligned OS versions, NSURL parsing has updated from the obsolete RFC 1738/1808 parsing to the same RFC 3986 parsing as NSURLComponents. This unifies the parsing behaviors of the NSURL and NSURLComponents APIs. Now, NSURL automatically percent- and IDNA-encodes invalid characters to help create a valid URL.
サーバ側、Railsがparamsに収める時点で1回URLのデコードが入っていますが、
# これまでの問題ないパターン
{ ..., trade_tabs: "[2, 4]" }
# 当該OS当該verのパターン
{ ..., trade_tabs: "[2,%204]" }
# (本当は生Hashじゃないんですけど概念的な記述と思ってください)
という文字列になっていて、その後Arrayに変換(JSON.parse
)する時に失敗して、アプリケーションエラーを返されていた、というのが今回の不具合となります。
なお、リクエストに空白が入っていなければエラーが起こらず、配列要素数1で同APIをリクエストしている場面では、,
が入らないので、当該OS当該verでも問題なくアクセスできていました。
また、問題があったのはGETリクエストでURLに付加されたパラメータのみで、POSTリクエストのbodyについては問題ありませんでした。
回避策
クライアント側はUnityの対応&バージョンアップを待つとして、サーバ側で回避策を講じます。
GETで受け取ったparamsのvalueに%xx
が含まれていたら、もう一度デコードが必要とみなしてURI.decode_www_form_componentを噛ませるようにしました。
今回は問題が発生した%20
決め打ちとしました。
def patched_uri_decode(str)
if request.get? && str&.include?("%20")
URI.decode_www_form_component(str)
else
str
end
end
Discussion