【Unity】アプリのバイブレーション制御

f:id:nuakam:20180924115239j:plain




バイブレーション制御

ボタンを押したことを知らせるバイブレーションを作りたい。
バイブレーションは端末側の機能なのでIOS,Android,といったOSによって別々に書かなくてはならない。
(一応unityでもサポートされてるといえばされてるけど、1秒固定で使い勝手が悪いのだ。)


環境

windows10
unity 2017 1.0.p5 personal

Android

ネイティブコードは規定のフォルダ内に収めなくてはエラーが起こる。
まずはネイティブを入れるフォルダ管理から。

フォルダ管理

(なければ)project 内にPluginsフォルダを作る。pluginsフォルダ内にAndroidフォルダを作る。

f:id:nuakam:20171120091714p:plain

こんな感じに。詳しいことはネットに色々落ちてるから省略。

コーディング

AndroidのネイティブはUnityとの連携が上手くいかなかったので、javaは諦めてC#プラグインで書くことにする。

さっきのAndroidフォルダ内に
VibrateAndroid.csとしてこんな感じに

using UnityEngine;
using System.Collections;

public static class Vibration
{

#if UNITY_ANDROID && !UNITY_EDITOR
    public static AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    public static AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
    public static AndroidJavaObject vibrator = currentActivity.Call<AndroidJavaObject>("getSystemService", "vibrator");
#else
    public static AndroidJavaClass unityPlayer;
    public static AndroidJavaObject currentActivity;
    public static AndroidJavaObject vibrator;
#endif

    public static void Vibrate()
    {
        if (isAndroid())
            vibrator.Call("vibrate");
        else
            Handheld.Vibrate();
    }
    private static bool isAndroid()
    {
#if UNITY_ANDROID && !UNITY_EDITOR
	return true;
#else
        return false;
#endif

これでVibrate.Vibrate()呼び出せばAndroidがブルブルする。


振動秒数を調節したければ

    public static void Vibrate(long milliseconds)
    {
        if (isAndroid())
            vibrator.Call("vibrate", milliseconds);
        else
            Handheld.Vibrate();
    }

こんな関数をclass内に追加すれば
Vibration.Vibrate(500);
なんかで500マイクロ秒振動できる。

iOS

iOSはAndroidほどの自由度はない。できることは連続振動と0.5秒ほどの振動だけ。
やり方はAndroidと同様に、フォルダをPlugins内に作る。
iOS内に作るファイルは2つ。

1.c#ファイル
2.橋渡しのmmファイル


まずはc#から。

using System.Runtime.InteropServices;

namespace Iphone.vib
{
    /// <summary>
    /// iOSバイブレーションネイティブプラグイン
    /// </summary>
    public static class VibrationPlugin
    {
        #if !UNITY_EDITOR && UNITY_IOS
        [DllImport("__Internal")]
        static extern void _PlayVibration (int i);
        #endif
        
        public static void PlayVibration(int frequency)
        {
          
            #if !UNITY_EDITOR && UNITY_IOS
            _PlayVibration(frequency);
            #endif
        }
    }
}

だいたいこんな感じ。
ファイル名にVibrationPlugin.csとでもつけて保存。


ファイル名に一貫性がない。(´・ω・`)
絶対あとでわけわからんくなる。(´・ω・`)

次に.mmファイル。
.mmはc++とobjectiv-cの合体させたiOSアプリファイルだよーって聞くけど、詳しいことは謎。

VibrationPluginBridge.mmとでもつけて作成

#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioServices.h>

extern "C"
{
    int cnt = 1;
    void ExecuteVibration(SystemSoundID ssID,void *clientData)
    {
        if (cnt > 0)
        {
            [NSThread sleepForTimeInterval:(NSTimeInterval)1.0];
            AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
        }
        else{
            AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
         
		}
        cnt--;
    }
    
    void _PlayVibration(int i)
    {
        cnt = i;
        AudioServicesAddSystemSoundCompletion(kSystemSoundID_Vibrate,NULL,NULL,ExecuteVibration,NULL);
         AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

   }	
}

これでVibrationPlugin.PlayVibration(0);で1度振動。 数を増やすと連続振動する。
これより短い振動を使いたい場合は、ゴリ押しだけど内部で定義されたものを無理やり使う。
ざっと調べたところ、ショートメールが来たときの振動が一番短いと思う。


mmファイルの

 AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

AudioServicesAddSystemSoundCompletion(kSystemSoundID_Vibrate,NULL,NULL,ExecuteVibration,NULL);

を全て削除なりコメントアウトなりして、

	 AudioServicesPlaySystemSound(1003);
	AudioServicesDisposeSystemSoundID(1003);

を書き加える。
するとIOSで最少時間のバイブレーションが鳴らせる。


もっと良いやり方があればぜひご教授を!!(`・ω・´)