- 投稿日:2019-03-05T22:00:59+09:00
JSONArray、JSONObjectの判定
JSONArray、JSONObjectの判定
JSONファイルの中身が配列なのか単体なのか?ってこと
というわけで、パッとおもいつきでかいたのがこんなかんじ。
1文字目が [ だったらとりあえずJSONArrayだなって判断する。
その文字列がパーサ通るかは別としてね。if(jsonStr.charAt(0) == '[') { //JSONArray } else if(jsonStr.charAt(0) == '{') { //JSONObject }もっとスマートなやり方ないかなーって探してたらこういうのがあったよ
Object object = new JSONTokener(data).nextValue(); if (object instanceof JSONArray) { //JSONArray } else if (object instanceof JSONObject) { //JSONObject }こっちのほうががいいかんじ
おわり
- 投稿日:2019-03-05T20:01:11+09:00
Espressoのperform(click())とはなにか
Espressoとは、Googleが公開しているAndroid用のUIテスティングフレームワークです。
https://developer.android.com/training/testing/espresso
使い方は以下のように、
onView
でViewを指定して、perform
で操作を行って、check
で照合します。Sample.java@Test public void greeterSaysHello() { onView(withId(R.id.name_field)).perform(typeText("Steve")); onView(withId(R.id.greet_button)).perform(click()); onView(withText("Hello Steve!")).check(matches(isDisplayed())); }わかりやすい仕組みなので導入は簡単なのですが、
使用頻度の高いperform(click())
を使っていると「
perform(click())
どういう仕組みなんだ..?」とモヤモヤしたので
perform(click())
のソースコードの処理を追ってみました。
Android SDK28、EspressoのバージョンはAndroidXの3.1.1で調べています。click()の種類
https://developer.android.com/reference/android/support/test/espresso/action/ViewActions
androidx.test.espresso.action.ViewActions
にはclickメソッドが3つあります。
サンプルコードにあるのは一番目の引数なしのものです。
- click()
- click(int inputDevice, int buttonState)
- click(ViewAction rollbackAction)
APIリファレンスには
click()
は以下と同様と書いてあります。
click(InputDevice.SOURCE_UNKNOWN, MotionEvent.BUTTON_PRIMARY)
二つの引数の概要は以下となります。InputDevice
https://developer.android.com/reference/android/view/InputDevice.html
InputDeviceはAndroid本体の定数で入力デバイスを表す定数群です。
SOURCE_
の前置詞がつくものははビットフラグになっており、SOURCE_UNKNOWN
他にSOURCE_KEYBOARD
,SOURCE_DPAD
,
SOURCE_TOUCHSCREEN
など入力元を表していることがわかります。
click()
ではSOURCE_UNKNOWN
なので入力元を特定していないようです。MotionEvent
https://developer.android.com/reference/android/view/MotionEvent.html
MotionEventはAndroid本体の定数で入力デバイスを表すビットフラグです。
BUTTON_
の前置詞を持つものはボタン用の定数で以下7つがあります。
Key Description BUTTON_PRIMARY
Button constant: Primary button (left mouse button). BUTTON_SECONDARY
Button constant: Secondary button (right mouse button). BUTTON_TERTIARY
Button constant: Tertiary button (middle mouse button). BUTTON_BACK
Button constant: Back button pressed (mouse back button). BUTTON_FORWARD
Button constant: Forward button pressed (mouse forward button). BUTTON_STYLUS_PRIMARY
Button constant: Primary stylus button pressed. BUTTON_STYLUS_SECONDARY
Button constant: Secondary stylus button pressed.
click()
ではBUTTON_PRIMARY
なのでマウスの左クリックに相当する、通常のクリック処理のようです。click()の処理
ViewActionsにあるclick()は以下の箇所になります。
各設定を指定したGeneralClickActionのインスタンスを作成し、アサートを行ったあとに返しています。: public static ViewAction click() { return actionWithAssertions( new GeneralClickAction( Tap.SINGLE, GeneralLocation.VISIBLE_CENTER, Press.FINGER, InputDevice.SOURCE_UNKNOWN, MotionEvent.BUTTON_PRIMARY)); } :GeneralClickActionの引数
第1引数: Tap
以下3つがあります。
Key Description SINGLE シングルタップ LONG ロングタップ DOUBLE ダブルタップ 定数ではなくEnumです。Tapperをimplementし、
それぞれperform時の処理が書かれています。Tap.javapublic enum Tap implements Tapper { SINGLE { @Override public Tapper.Status sendTap( UiController uiController, float[] coordinates, float[] precision) { return sendTap(uiController, coordinates, precision, 0, 0); } :第2引数: GeneralLocation
Key Description TOP_LEFT Viewの左上 TOP_CENTER Viewの上中央 TOP_RIGHT Viewの右上 CENTER_LEFT Viewの左中央 CENTER Viewの中央 CENTER_RIGHT Viewの右中央 BOTTOM_LEFT Viewの左下 BOTTOM_CENTER Viewの下中央 BOTTOM_RIGHT Viewの右下 VISIBLE_CENTER 見える範囲のViewの中央 こちらも定数ではなくEnumです。CoordinatesProviderをimplementしています。
click()に使用されているVISIBLE_CENTER
だけ見える範囲と特殊ですが基本的にはViewの座標を取得できるようになっています。GeneralLocation.javapublic enum GeneralLocation implements CoordinatesProvider { TOP_LEFT { @Override public float[] calculateCoordinates(View view) { return getCoordinates(view, Position.BEGIN, Position.BEGIN); } }, :第3引数: Press
Key Size (mm) Comment PINPOINT 1x1 FINGER 16x16 average width of the index finger is 16 – 20 mm. THUMB 25x25 average width of an adult thumb is 25 mm (1 inch). 同じくEnumです。クリックエリアを返すためのPrecisionDescriberをimplementしています。
click()ではFINGER
なので16x16mmのタップとして認識されるようです。
上を見るに親指も選択できます。
16mmは若干大きすぎる気がします..。public enum Press implements PrecisionDescriber { PINPOINT { @Override public float[] describePrecision() { float[] pinpoint = {1f, 1f}; return pinpoint; } }, :第4引数、第5引数は上述なので省略。
次はGeneralClickActionの処理を追ってみます。perform(click())の処理
前編 - クリック処理の概要
https://developer.android.com/reference/android/support/test/espresso/ViewAction
https://developer.android.com/reference/android/support/test/espresso/action/GeneralClickAction.html
GeneralClickAction
のperform処理のソースコードには
RPGの置き手紙イベントのような大きめのコメントがあります。コメント部分を訳してみました。
ネイティブイベントの注入はかなり面倒なプロセスです。 「タップ」は実際には、システムに2つ別々に注入する必要があるモーションイベントです。 注入はテスト対象のアプリからAndroidシステムサーバーにRPC呼び出しを行います。 システムサーバーはどのウィンドウ層にイベントを配信するかを決定し、そのウィンドウ層にRPCを作成し、 そのウィンドウレイヤーはイベントを正しいUI要素、アクティビティ、またはウィンドウオブジェクトに配信します。 今回はダウン・アップのためにこれを2回繰り返します。 あっ、ダウンイベントはイベントが長押しか短押しかどうかを検出するためにタイマーをトリガします。 アップイベントを受信した瞬間にタイマーが削除されます。 (注:eventTimeが将来になる可能性はほとんどのモーションイベントプロセッサでは完全に無視されます) ふぅ。 この結果として、通常のタップを実行したい場合に、 何らかの理由でタップのアップイベント(後半)が長押しタイムアウト(システム負荷による)の後に配信され、 長押しの動作が表示されることがあります。(例:コンテキストメニューの表示) これを優雅に回避または処理する方法はありません。 また、長押しの動作はアプリ/ウィジェット固有のものです。 短押しとは異なる長押しの動作がある場合は、実行時に長押しの効果を元に戻す「'RollBack' ViewAction」を渡すことができます。要するに
click()
では指をつける-はなすの2つのイベントをすばやく発行することで
「クリック操作」をしているとのこと。以下3つのコードから、
MotionEvent#obtain
でAndroidのモーションイベントを作成し、
UiController#injectMotionEvent
でイベントを注入している事がわかります。
- 1. androidx.test.espresso.action.GeneralClickAction
- 2. androidx.test.espresso.action.Tap
- 3. androidx.test.espresso.action.MotionEvents
呼び出し階層をまとめると以下のようになります。
下記の中でMotionEventがAndroidSDKの処理。その他はEspressoの処理となります。- GeneralClickAction#perform - Tap#sendSingleTap - MotionEvents#sendDown - MotionEvent#obtain //ダウンイベントの作成 - UiController#injectMotionEvent //ダウンイベントの注入 - MotionEvents#sendUp - MotionEvent#obtain //アップイベントの作成 - UiController#injectMotionEvent //アップイベントの注入ここまでで
click()
を実現するための要素がわかりました。後編 - イベントの注入方法
実際に
injectMotionEvent
部分でどのようにイベントを注入しているか見ていきます。Espressoは内部でDaggerを使用しており、
UiController
はインターフェイスで外から注入する形となっています。
そのためinjectMotionEvent
呼び出し以降のコードは少し追いづらくなっています。
以下の順でソースコードを追いました。
- 1. androidx.test.espresso.base.UiControllerModule
- 2. androidx.test.espresso.base.UiControllerImpl
- 3. androidx.test.espresso.Espresso
- 4. androidx.test.espresso.BaseLayerComponent (classes.jar)
- 5. androidx.test.espresso.GraphHolder (classes.jar)
- 6. androidx.test.espresso.base.BaseLayerModule
- 7. androidx.test.espresso.base.InputManagerEventInjectionStrategy
上記から実処理がある
BaseLayerModule
、InputManagerEventInjectionStrategy
に絞って説明します。BaseLayerModule
以下はBaseLayerModuleで、EventInjectorを提供している
provideEventInjector
メソッドを抜粋したものです。
このクラスはDaggerのModuleに属するため、エントリポイントのEspressoクラスからBaseLayerComponent経由で呼ばれます。
MotionEventをinjectするためのEventInjectorに必要なEventInjectionStrategyを作成しています。SDK Version16以上ではInputManager、7から15ではWindowManagerを使用する処理になっています。
BaseLayerModule.java: @Provides @Singleton public EventInjector provideEventInjector() { // On API 16 and above, android uses input manager to inject events. On API < 16, // they use Window Manager. So we need to create our InjectionStrategy depending on the api // level. Instrumentation does not check if the event presses went through by checking the // boolean return value of injectInputEvent, which is why we created this class to better // handle lost/dropped press events. Instrumentation cannot be used as a fallback strategy, // since this will be executed on the main thread. int sdkVersion = Build.VERSION.SDK_INT; EventInjectionStrategy injectionStrategy = null; if (sdkVersion >= 16) { // Use InputManager for API level 16 and up. InputManagerEventInjectionStrategy strategy = new InputManagerEventInjectionStrategy(); strategy.initialize(); injectionStrategy = strategy; } else if (sdkVersion >= 7) { // else Use WindowManager for API level 15 through 7. WindowManagerEventInjectionStrategy strategy = new WindowManagerEventInjectionStrategy(); strategy.initialize(); injectionStrategy = strategy; } else { throw new RuntimeException( "API Level 6 and below is not supported. You are running: " + sdkVersion); } return new EventInjector(injectionStrategy); } :昨今はSDK Version16以上が一般的なので
InputManagerEventInjectionStrategyの処理を追います。InputManagerEventInjectionStrategy
このクラスに実際のイベントを実行する処理が書いてあります。
以下のメソッドを抜粋します。
- initialize
- innerInjectMotionEvent
InputManagerEventInjectionStrategy#initialize
InputManagerEventInjectionStrategyの初期化処理です。
InputManagerの非公開メソッドである
android.hardware.input.InputManager#injectInputEvent
をリフレクションにより呼び出せるようにしています。: void initialize() { if (initComplete) { return; } try { Log.d(TAG, "Creating injection strategy with input manager."); // Get the InputManager class object and initialize if necessary. Class<?> inputManagerClassObject = Class.forName("android.hardware.input.InputManager"); Method getInstanceMethod = inputManagerClassObject.getDeclaredMethod("getInstance"); getInstanceMethod.setAccessible(true); instanceInputManagerObject = getInstanceMethod.invoke(inputManagerClassObject); injectInputEventMethod = instanceInputManagerObject .getClass() .getDeclaredMethod("injectInputEvent", InputEvent.class, Integer.TYPE); injectInputEventMethod.setAccessible(true); // Setting event mode to INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH to ensure // that we've dispatched the event and any side effects its had on the view hierarchy // have occurred. Field motionEventModeField = inputManagerClassObject.getField("INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH"); motionEventModeField.setAccessible(true); syncEventMode = motionEventModeField.getInt(inputManagerClassObject); if (Build.VERSION.SDK_INT >= 28) { // Starting from android P it is not allowed to access this field with reflection, hardcoded // this value as workaround. asyncEventMode = 0; } else { Field asyncMotionEventModeField = inputManagerClassObject.getField("INJECT_INPUT_EVENT_MODE_ASYNC"); asyncMotionEventModeField.setAccessible(true); asyncEventMode = asyncMotionEventModeField.getInt(inputManagerClassObject); } setSourceMotionMethod = MotionEvent.class.getDeclaredMethod("setSource", Integer.TYPE); initComplete = true; } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } } :InputManagerEventInjectionStrategy#innerInjectMotionEvent
実際にモーションイベントを注入しているメソッド
innerInjectMotionEvent
が以下です。以下箇所で、
initialize()
で準備したInputManager#injectInputEvent
の実行を確認することができました。
injectInputEventMethod.invoke(instanceInputManagerObject, motionEvent, eventMode);
# ちなみに
isFromTouchpadInGlassDevice
はGoogleグラスの判定です(!)InputManagerEventInjectionStrategy.java: private boolean innerInjectMotionEvent(MotionEvent motionEvent, boolean shouldRetry, boolean sync) throws InjectEventSecurityException { try { // Need to set the event source to touch screen, otherwise the input can be ignored even // though injecting it would be successful. // TODO: proper handling of events from a trackball (SOURCE_TRACKBALL) and joystick. if ((motionEvent.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0 && !isFromTouchpadInGlassDevice(motionEvent)) { // Need to do runtime invocation of setSource because it was not added until 2.3_r1. setSourceMotionMethod.invoke(motionEvent, InputDevice.SOURCE_TOUCHSCREEN); } int eventMode = sync ? syncEventMode : asyncEventMode; return (Boolean) injectInputEventMethod.invoke(instanceInputManagerObject, motionEvent, eventMode); } catch (IllegalAccessException e) { : //例外処理が長く続くので省略 } :上記処理が
UiController#injectMotionEvent
呼び出し時の処理となり
perform(click())
が実現されるようです。まとめ - Espressoのperform(click())とは
どういうものなのか
以下の5つの条件に当てはまる操作
- 入力デバイスについては特定しない (
InputDevice.SOURCE_UNKNOWN
)- マウスの左クリックに相当するボタンを押すアクション (
MotionEvent.BUTTON_PRIMARY
)- ロングタップやダブルタップではい (
Tap.SINGLE
)- 見える場所の中央座標を対象としている (
GeneralLocation.VISIBLE_CENTER
)- 範囲は16x16mmの人差し指相当 (
Press.FINGER
)どういう処理なのか
click()
ではGeneralClickActionを作成しアサートしているperform()
時にGeneralClickActionからMotionEvent#obtain
でイベント作成し本体アプリに注入している
- DOWNイベントとUPイベントの2つのイベントを発行している
- 注入方法は
android.hardware.input.InputManager#injectInputEvent
のリフレクション
- 投稿日:2019-03-05T18:59:46+09:00
【Unity】スワイプ、フリックで分岐するSafari風スクロール【C#】
【Unity】スワイプ、フリックで分岐するSafari風スクロール【C#】
はじめに
スワイプした分スクロールできて、かつフリックすると速度をもってスクロールできる、iOS標準ブラウザのSafari風のUXのスクロール方法を実装したい!
ついでに2本指での拡大と縮小も実装しました。(なぜ?)
応用時はクランプなど用いてスクロール範囲を制御してください。荒い実装ではありますが、そこそこ良い動きになったので備忘録かつ共有。
開発環境
OS: MacOS Mojave
開発環境: Unity 2018.2.14f1 personal
開発言語: C#ソースコードとその説明
SwipeManager.csusing System.Collections; using System.Collections.Generic; using UnityEngine; public class SwipeManager : MonoBehaviour { //フリック時のスピード private float x_speed = 0; private float y_speed = 0; //カメラ拡大縮小時のスピード(実装環境によって要調整) private float cameraSpeed = 0.4f; //初期位置 private Vector2 startPos; //最初のタップからの経過時間 private float duration = 0; //オブジェクトの移動比率を操作する変数(実装環境によって要調整) private float moveRatio = 0.5f; //スワイプするオブジェクト(この場合スクロールビューのコンテンツ)の外部参照 public GameObject obj; //拡大縮小用カメラの外部参照 public Camera cam; void Update() { //経過時間の計算 duration += Time.deltaTime; //一本指での操作(スワイプ、フリック) if(Input.touchCount == 1){ //タップ情報の取得 Touch touch = Input.GetTouch(0); //タップ状態の分岐 switch(touch.phase){ //タップ開始 case TouchPhase.Began: //タッチ開始座標、時間取得 this.startPos = Input.mousePosition; duration = 0; break; //タップ中、指が動いている case TouchPhase.Moved: //オブジェクト移動(スワイプ) Vector3 nowPosi = obj.transform.localPosition; nowPosi.x = nowPosi.x - touch.deltaPosition.x*moveRatio; nowPosi.y = nowPosi.y - touch.deltaPosition.y*moveRatio; obj.transform.localPosition = nowPosi; break; //タップ終了 case TouchPhase.Ended: //タップ終了位置取得 Vector2 endPos = Input.mousePosition; //触れていた秒数でフリックとスワイプ分岐 if(duration <= 0.5){ float x_flickLength = endPos.x - this.startPos.x; float y_flickLength = endPos.y - this.startPos.y; // フリックの長さを速度に変換する this.x_speed = x_flickLength / 500.0f; this.y_speed = y_flickLength / 500.0f; }else{ //フリック判定じゃない場合はcameraのTranslate速度を0にする this.x_speed = 0; this.y_speed = 0; } break; } } //オブジェクト移動(フリック) obj.transform.Translate(this.x_speed, this.y_speed, 0); //毎フレーム減速させる this.x_speed *= 0.8f; this.y_speed *= 0.8f; //2本指での操作(ピンチイン、アウト) if (Input.touchCount == 2){ // 両方のタップ情報を取得 Touch touchZero = Input.GetTouch(0); Touch touchOne = Input.GetTouch(1); // 前フレームでのタップ位置 Vector2 touchZeroPrePos = touchZero.position - touchZero.deltaPosition; Vector2 touchOnePrePos = touchOne.position - touchOne.deltaPosition; // 各フレームのタッチ間の距離 float preTouchDeltaMag = (touchZeroPrePos - touchOnePrePos).magnitude; float touchDeltaMag = (touchZero.position - touchOne.position).magnitude; //各フレーム間の距離の差 float deltaMagnitudeDif = preTouchDeltaMag - touchDeltaMag; //タッチ間の距離の変化からカメラの平行投影サイズを変更 cam.orthographicSize += deltaMagnitudeDif * cameraSpeed; // 平行投影サイズは0以上になるようにする(クランプの範囲は要調整) cam.orthographicSize = Mathf.Clamp(cam.orthographicSize, 0f , 2.0f); } } }終わりに
TouchScriptなどの便利なアセットを使用するとおそらく早かったのですが、スクリプトで実装してもそこまで時間がかからないのと、自分でスクリプトを書いた方が拡張性に富むと思ったのでこのような実装をしました。どなたかの助けになれば幸いです。
参考文献
「フリックとスワイプの違い」
https://enjoy.sso.biglobe.ne.jp/archives/swipe_flick/
「Unity C#で時間の取得」
http://webbeginner.hatenablog.com/entry/2015/09/04/053623
「ピンチによる拡大」
https://unity3d.com/jp/learn/tutorials/topics/mobile-touch/pinch-zoom
「【Unity2D】スワイプでオブジェクトを上下左右自由自在に動かす方法」
https://miyagame.net/swipe/
- 投稿日:2019-03-05T17:01:19+09:00
flutter doctor で [✗] Android toolchain - develop for Android devices の対処
~/Library/Android/sdk/tools/bin/sdkmanager --licenses
で all y をやったら動いた.android つらい
参考
https://github.com/flutter/flutter/issues/16280#issuecomment-380447597
- 投稿日:2019-03-05T16:33:19+09:00
Debian noroot 環境に plank を導入する
はじめに
Debian noroot とは、 Android OS 上において root 権限を取ることなく Debian 環境を構築するためのアプリケーションです。
CPU の性能とメモリ容量が潤沢にある Android OS 端末であれば、 Debian noroot の導入によって Android OS 端末上で非常に軽快な Debian 環境を実現することが出来ます。
Debianのデスクトップ環境において、 Dock ランチャーソフトウェアを導入する事は、通常頻繁に使用するソフトウェアの起動を容易にする等、デスクトップ環境の利便性の向上に関して非常に有用となります。
ここで、Debianのデスクトップ環境において、軽量な Dock ランチャーソフトウェアの1つとして plank が挙げられます。
しかし、 Debian Jessie をベースにした Debian noroot 環境においては、 plank を導入するための適切な deb パッケージが存在しません。
そこで、 plank をソースコードからビルドし、MATE 環境の起動時において自動起動を行うように設定した所、Debian noroot 環境上における各種デスクトップ環境において plank を使用する事が出来るようになりました。
本稿では、 Debian noroot 環境における plank の導入手法について述べます。
本稿では最初に、 "plank の導入" の章において、軽量な Dock ランチャーソフトウェアである plank の Debian noroot 環境への導入手法について述べます。
次に、 "デスクトップ環境への導入" の章において、前章で導入した plank を Debian noroot 環境上の各種デスクトップ環境へ導入する手法について述べます。
そして、 "plank の問題点" の章において、現時点での Debian noroot 環境に導入した plank の問題点について述べます。
最後に、 "結論" の章において、本稿の結論について述べます。
plank の導入
本章においては、最初に、 "plank に依存するパッケージの導入" の節において、 Debian noroot 環境に plank を導入する際に、予め導入するべき plank の依存パッケージの導入について述べます。
次に、 "plank の実行ファイル等のビルド" の節において、 plank 本体のソースコードの取得と、 Debian noroot 環境上で plank 本体のソースコードから plank の実行ファイル等のビルドを行う手法について述べます。
最後に、 "plank のインストール" の節において、前節においてソースコードからビルドした plank の実行ファイル等を Debian noroot 環境上にインストールする手法について述べます。
plank に依存するパッケージの導入
まず最初に、 Debian noroot 環境において plank をビルドする上で、 plank に依存する Debian パッケージの導入を以下の通りに行います。
$ sudo apt-get install automake gnome-common intltool pkg-config valac libbamf3-dev libdbusmenu-gtk3-dev libgdk-pixbuf2.0-dev libgee-dev libglib2.0-dev libgtk-3-dev libwnck-3-dev libx11-dev libgee-0.8-devまた、上記に加えて、パッケージ
xstow
の導入も以下の通りに併せて行います。これは、ソースコードからビルドした plank の実行ファイル等をディレクトリ/usr/local
以下に導入する際に plank の実行ファイル等の管理を容易にする為です。$ sudo apt-get install xstowplank の実行ファイル等のビルド
次に、 plank 本体のソースコードをplank の公式ページより取得します。なお本稿では、 plank のバージョン 0.11.4 のソースコードである
plank-0.11.4.tar.xz
を以下の通りに取得します。plank のソースコードの取得が完了した後は、 plank のソースコードである
plank-0.11.4.tar.xz
を適切なディレクトリに展開します。$ cd /path/to/build # (ここに、 /path/to/build は、 plank の実行ファイル等をビルドするための作業ディレクトリ。) $ wget https://launchpad.net/plank/1.0/0.11.4/+download/plank-0.11.4.tar.xz $ tar -Jxvf plank-0.11.4.tar.xzそして、カレントディレクトリを
./plank-0.11.4
に移動して、以下の通りにソースコードから実行ファイル等をビルドします。ここで、plank のインストール先となるディレクトリは、前節で述べた
xstow
によって plank の管理を容易にする為に/usr/local/opt/plank-0.11.4
とします。$ cd ./plank-0.11.4 $ ./configure --prefix=/usr/local/opt/plank-0.11.4 --disable-silent-rules $ makeplank のインストール
前節によって、正常に plank の実行ファイル等のビルドが完了した後は、コマンド
make install
を実行して、 plank の実行ファイル等を/usr/local/opt/plank-0.11.4
にインストールします。$ make installそして、カレントディレクトリを
/usr/local/opt
に移動して以下のコマンドを実行します。コマンドxstow -v ./plank-0.11.4
の実行により、 plank の実行ファイル等のシンボリックリンクがディレクトリ/usr/local
以下に張られます。$ cd /usr/local/opt $ xstow -v ./plank-0.11.4 ...(略)... $最後に、以下の通りに
plank
コマンドを実行して、正常に plank が起動する事を確認します。$ plankなお、もし plank のソースコードをコンパイルする事が煩わしい場合や何らかの問題で困難である場合は、次に示す URL に置かれているシェルスクリプトを用いて、以下のように plank のソースコードのダウンロード及びビルドとインストールを自動的に行っても構いません。
- build-plank.sh (最新版)
$ bash -c "$(wget -q -O - https://git.io/debian-noroot-build-plank.sh)" ...(略)... $ plank # (plank の動作確認を行う。)デスクトップ環境への導入
本章では、前章で述べた手法でインストールした plank を Debian noroot 環境上の各種デスクトップ環境の起動時において自動的に起動するように設定する手法について述べます。
まず、 "MATE への導入" の節において、 Linux MINT において採用されているデスクトップ環境である MATE に plank を導入する手法について述べます。
次に、 "LXDE への導入" の節において、軽量なデスクトップ環境の1つである LXDE に plank を導入する手法について述べます。
最後に、 "xfce4 への導入" の節において、 Debian noroot 環境におけるデフォルトのデスクトップ環境である xfce4 に plank を導入する手法について述べます。
なお、以降で述べる設定手法で示す各画像において表示されている plank については、 plank の動作確認時において plank の各種設定を修正したものであり、デフォルトの plank の表示とは若干異なることに留意して下さい。
MATE への導入
まず、 plank をデスクトップ環境 MATE において自動的に起動するように設定する手法について述べます。
- まず最初に、以下の画像のようにして [設定] のメニューを開き、 [コントロールセンター] の項目を選択します。
![]()
- 次に、以下の画像のように [コントロールセンター] のパネルにおいて、 [自動起動するアプリ] のボタンをクリックします。
![]()
- そして、以下の画像のように [自動起動するアプリの設定] のウィンドウにおいて、 [追加]のボタンをクリックします。
![]()
- その後、以下の画像のように [自動起動するプログラムの編集] のウィンドウにおいて、 plank の自動起動についての各項目を指定します。ここで、plank の実行ファイルの絶対パスは、必ず
/usr/local/bin/plank
とする必要があります。![]()
以上の設定が完了した後、 Debian noroot 環境を再起動して、以下の画像の通りに plank が自動的に起動する事を確認します。
LXDE への導入
次に、 plank を軽量なデスクトップ環境 LXDE において自動的に起動するように設定する手法について述べます。
- まず最初に、以下の画像のようにして [設定] のメニューを開き、 [LXSession のデフォルトのアプリケーション] の項目を選択します。
![]()
- ここで、 [LXSession Configuration] のウィンドウが開くので [Autostart] の項目を選択します。
![]()
- すると、以下の画像のように Manual Autostart Application のリストの末尾に [追加] のボタンと、その右隣にてテキストエリアが表示されているので、ここでテキストエリア内に
@plank
と入力して [追加] ボタンを押します。![]()
- [追加] ボタンを押した後、以下の画像のように Manual Autostart Application のリストの末尾に
@plank
が登録されていることを確認します。![]()
以上の設定が完了した後、 Debian noroot 環境を再起動して、 plank が自動的に起動する事を確認します。
fxce4 への導入
そして、plank を Debian noroot 環境のデフォルトのデスクトップ環境である [fxce4 環境][FXCE]において自動的に起動するように設定する手法について述べます。
- まず最初に、以下の画像のようにして [設定] のメニューを開き、 [セッションと起動] の項目を選択します。
![]()
- そして、以下の画像のように [セッションと起動] のウィンドウにおいて、[自動開始アプリケーション] の項目を選択します。
![]()
- すると、以下の画像のように自動起動するアプリケーションの一覧が表示されます。ここで、未だ plank が一覧に登録されていない場合は [追加] ボタンを押し、登録されている場合は plank が登録されている行をクリックして [編集] ボタンを押します。
![]()
- その後、以下の画像のように [アプリケーションの編集] のウィンドウにおいて、 plank の自動起動についての各項目を指定します。ここで、plank の実行ファイルの絶対パスは、必ず
/usr/local/bin/plank
とする必要があります。![]()
以上の設定が完了した後、 Debian noroot 環境を再起動して、 plank が自動的に起動する事を確認します。
plank に関する問題点
本章において、 plank について、現時点で判明してい問題点について述べます。
まず、何らかの理由で plank のプロセスに SIGKILL 等の SIGTERM でないシグナルが送られる事により異常終了した場合等において、再度 plank を起動した場合に以下のエラーメッセージを出力して plank が起動しない場合があります。
$ plank ...(略)... [ERROR 01:22:33.123456] [Utils:42] GSettingsSchema 'net.launchpad.plank' not found Trace/breakpoint trap $この場合は以下のコマンドの実行により、 plank が起動しない問題を回避します。
$ sudo glib-compile-schemas /usr/local/share/glib-2.0/schemas上記のコマンドの実行によっても、問題が回避できない場合は、 plank のビルド及びインストールを再度行って下さい。
結論
本稿では、 "plank の導入" の章において、 Debian noroot 環境上で、 plank のソースコードから、実行ファイル等をビルドし、ディレクトリ
/usr/local
以下にインストールする手法について示しました。そして、 "デスクトップ環境への導入" の章において、 "plank の導入" の章でインストールした plank を、 Debian noroot 環境上で動作する各種デスクトップ環境の起動時に自動的に起動させるように設定を行う手法について示しました。
以上で示した手法によって Debian noroot 環境へ plank を導入することにより、 Debian noroot 環境の起動時に軽量な Dock ランチャーソフトウェアである plank が自動的に起動して、高頻度で使用するソフトウェアの起動が容易になることが示されました。
また、デスクトップ環境 MATE が導入された Debian noroot 環境において、 plank を左端の中央に配置する設定を行うことにより、 Unity ライクなデスクトップ環境の外観が実現でき、多くの PC 端末と同様の快適性を持つデスクトップ環境が実現できることが判りました。
謝辞
本稿の記述に当たって、 Android OS 端末上で非常に軽快な Debian 環境を実現することを可能にした Debian noroot 環境の開発者である pelya 氏に心より感謝致します。
なお、 plank 本体をソースコードから実行ファイル等へビルドし、インストールを行う手法に関しては、techbar 氏による "Installing Plank Dock on Debian Jessie | Techbear" を参考にしました。 techbar 氏に心より感謝致します。
そして最後に、 Debian noroot 環境と Android OS 及び Debian 環境の全ての事に関わる全ての皆様に心より感謝致します。