【Unity】ネットワークに実際に繋がるか確認するサンプルコード

  • URLをコピーしました!
目次

はじめに

ネットワークに繋がって いる/いない のチェックは下記コードを使っていましたが、こちらは正確ではありませんでした。

if( Application.internetReachability != NetworkReachability.NotReachable )

公式に注意書きがありました。これは「機内モード」など、あくまで端末側の設定をチェックするもので、実際の接続をチェックするものではないとのこと。

注:このプロパティは、実際の接続性を判断するために使用しないでください。例:デバイスはホットスポットに接続されていても、ネットワークへの実際の経路を持っていないことがあります。

https://docs.unity3d.com/ScriptReference/Application-internetReachability.html

今回コードを見直したのでご紹介します。

サンプルコード

実際にネットワークに繋がっているかチェックするサンプルです。繋がっていればtrue、繋がっていなければfalseを返します。UniTaskを使います。

  • Unity 2021.3.11
  • UniTask 2.3.1
using UnityEngine;
using UnityEngine.Networking;
using Cysharp.Threading.Tasks;
using System;

//インターネット接続確認
public static class OnlineChecker {

	//テストアクセスするURL
	private static readonly string CHECK_TARGET_URL = "https://httpbin.org";

	public async static UniTask<bool> IsOnline(int timeOut = 3000)
	{

		if(Application.internetReachability == NetworkReachability.NotReachable) return false;

		bool bo = false;

		var request = new UnityWebRequest(CHECK_TARGET_URL);
		var task1 = request.SendWebRequest().ToUniTask();
		var task2 = UniTask.Delay(timeOut);

		try
		{
			DevLog.Log($"アクセス-開始 {CHECK_TARGET_URL}");

			var result = await UniTask.WhenAny(task1,task2);

			if(result.result.result == UnityWebRequest.Result.Success)
			{
				DevLog.Log($"アクセス-成功 {CHECK_TARGET_URL}");
				bo = true;
			}
		}
		catch(Exception e)
		{
			DevLog.LogWarning($"例外-失敗 {e}");
		}
		finally
		{
			await UniTask.WaitUntil(() => request.isDone);
			request.Dispose();
			DevLog.Log($"アクセス-廃棄");
		}

		return bo;
	}
}

コード解説

OnlineChecker クラスはシーンに配置する必要はありません。

public static class OnlineChecker

テストアクセスしている「httpbin」は通信テストに便利なWebサービスです。本番では所持しているサーバーなどに置き換えてください。

private static readonly string CHECK_TARGET_URL = “https://httpbin.org”;

ソフトアンテナ
httpbin - HTTP通信のテストに便利なWebサービス&ソフト | ソフトアンテナ Webプログラムの開発では、クライアンがどのようなパラメータを送信し、サーバーがどのようなレスポンスを返しているのか正確に理解している必要があります。 今回詳細する...

IsOnline() メソッドはタイムアウト用の int 値(デフォルト3秒)を引数にしていて、Unitak で Bool型を返しています。キャンセルは想定していていませんが、外部からキャンセルできるようにCancellationTokenを渡してもいいかもしれません。

public async static UniTask<bool> IsOnline( int timeOut = 3000 )

また、そもそも端末側でアクセス制限している場合はfalseを返します。

if(Application.internetReachability == NetworkReachability.NotReachable) return false;

Unityの過去バージョンではiOS14.2などでUnityWebRequest の timeoutが効かないことがあったようです。現在は修正されたようですが、、、

Unity Forum
UnityWebRequests on iOS sometimes get stuck indefinitely even with timeout set Hello, Using the latest Unity 2020.1.14f1 and iOS 14.2 unitywebrequests sometimes seem to get 'stuck' indefinitely, even with the timeout set to a low...
あわせて読みたい
Unity IssueTracker - [iOS] UnityWebRequest doesn't work when using a 14.2+ iOS device Reproduction steps: 1. Download and open the user's attached "ARFoundation2020Test.zip" project 2. Build and deploy the app to an iO...

、、、私の環境ではtimeoutは機能しましたが、エラーを返してフリーズしてしまったので、UnityWebRequestをUnitask化して、UniTask.WhenAny()でUniTask.Delay()と掛け合わせて、時間を制限するようにしました。

var request = new UnityWebRequest(CHECK_TARGET_URL);
var task1 = request.SendWebRequest().ToUniTask();
var task2 = UniTask.Delay(timeOut);

var result = await UniTask.WhenAny(task1,task2);

UnityWebRequest をインスタンスしてtry-catch-finallyを使って、アクセス-成功/失敗/廃棄を処理しています。アクセスに失敗したら false 、成功したら true を返します。

try
{
DevLog.Log($”アクセス-開始 {CHECK_TARGET_URL}”);

var result = await UniTask.WhenAny(task1,task2);

if(result.result.result == UnityWebRequest.Result.Success)
{
DevLog.Log($”アクセス-成功 {CHECK_TARGET_URL}”);
bo = true;
}
}
catch(Exception e)
{
DevLog.LogWarning($”アクセス-失敗 {e}”);
}
finally
{
await UniTask.WaitUntil(() => request.isDone);
request.Dispose();
DevLog.Log($”アクセス-廃棄”);
}

return bo;

つまずいたのは、request.Dispose()するタイミングです。UniTask.WhenAnyが終了してから若干遅延があるようで、request.isDoneを待ってからDisposeするようにしました。

await UniTask.WaitUntil(() => request.isDone);
request.Dispose();

使い方

任意の場所からOnlineChecker.IsOnline()を呼び出して、bool値を受け取り、分岐させて処理を実行します。タイムアウトの時間を3秒から変更したい場合は数値を指定してください。

void Start()
{
	_OnlineChecker().Forget();
}

//ネットワークチェック
async UniTaskVoid _OnlineChecker()
{
	var bo = await OnlineChecker.IsOnline(2000);

	if(bo)
	{
		Debug.Log("成功した処理");
	}
	else
	{
		Debug.Log("失敗した処理");
	}
}
あわせて読みたい
【Tips】Macで帯域制限をかけて通信速度を下げるテストがしたい 【はじめに】 Photon Fusion で開発中のアプリを通信環境の悪い状態でテストしたかったので、「Network Link Conditioner」を利用しました。「Network Link Conditioner...

参考

teratail[テラテイル]
Unityでネットのアクセス状況を調べてたい ### 前提・実現したいこと Unityでインターネットのアクセス状況を調べて処理を分岐させたいと 思っております。 ### 発生している問題・エラーメッセージ ネットで調べて...
(:3[kanのメモ帳]
本当にインターネットに接続出来るかを確認する方法【Unity】 - (:3[kanのメモ帳] この記事でのバージョン Unity 2021.1.16f1 はじめに UnityはApplication.internetReachabilityを使うことで、 インターネットのアクセス状態を返します。 簡単にインター...
あわせて読みたい
【ハルシオンブログ】なんかUnityWebRequestでエラーが出でたとき こんにちは。大坂です。UnityWebRequestでこんなエラーが出た時。A Native Collection has not been disposed, resulting in a memory leak. Allocated from:Unity.Collect...
はなちるのマイノート
【Unity】HttpClient,UnityWebRequestにタイムアウトを設定する方法 - はなちるのマイノート はじめに Unityで通信を行おうと思った場合、HttpClientもしくはUnityWebRequestのどちらかを使うことが多いでしょう。これらを用いるに当たってタイムアウト処理を設定し...

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次