Sony SmartWatch2用のウォッチフェイスの部品(ウィジェット)を実装するときに,少し手こずったところがありましたのでメモします

SW2用ウィジェット作成時の注意点

使用したSDK

のSony-Add-on-SDK_v3.0.zip (2016/2/25版)

完成したアプリ

前提

定期更新するウィジェットを実装すると,だいたいこんな感じになると思います.

これは,レイアウト mywidget.xml を表示して, そこに含まれるR.id.txtのテキストを定期更新する例です.

import com.sonyericsson.extras.liveware.extension.util.widget.BaseWidget;

public class MyWidget extends BaseWidget {
	private String extensionKey;

	public MyWidget(WidgetBundle bundle) {
		super(bundle);

		YtWidgetRegistrationInformation regInfo = new YtWidgetRegistrationInformation(mContext);
		extensionKey = regInfo.getExtensionKey();
	}

	@Override
	public void onStartRefresh() {
		// コンテンツ初期設定
		showLayout(R.layout.mywidget);
		// 定期更新の登録
		scheduleRepeatingRefresh(System.currentTimeMillis(), 10 * 1000, extensionKey);
	}

	@Override
	public void onStopRefresh() {
		// 定期更新の解除
		cancelScheduledRefresh(extensionKey);
	}

	@Override
	public void onScheduledRefresh() {
		// コンテンツの定期更新
		sendText(R.id.txt, "〜");
	}
	・・・
}

問題点

ウィジェットが1つだけならこれで問題ないのですが, アプリが複数のウィジェットを含んでいて,それらを複数同時にウォッチフェイスに貼り付けた場合に, どれか1つのウィジェットしか定期更新がかからないという問題が発生しました.

動きを見ると,各ウィジェットがAlarmManagerに設定しているPendingIntentが,キャンセルされているようなので, 次のように対応して,この問題は解消しました.

SDKのソースの改造です.

対策

SmartExtensionUtilsの, com.sonyericsson.extras.liveware.extension.util.widget.WidgetExtension

[変更前]

private PendingIntent createPendingRefreshIntent(String extensionKey) {
	Intent intent = new Intent(SCHEDULED_REFRESH_INTENT);
	intent.putExtra(Widget.Intents.EXTRA_EXTENSION_KEY, extensionKey);
	intent.putExtra(Widget.Intents.EXTRA_AHA_PACKAGE_NAME, mHostAppPackageName);
	intent.putExtra(Widget.Intents.EXTRA_INSTANCE_ID, mInstanceId);

	intent.setPackage(mContext.getPackageName());
	PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent,
			PendingIntent.FLAG_CANCEL_CURRENT);
	return pi;
}
[変更後]
private PendingIntent createPendingRefreshIntent(String extensionKey) {
	Intent intent = new Intent(SCHEDULED_REFRESH_INTENT);
	intent.putExtra(Widget.Intents.EXTRA_EXTENSION_KEY, extensionKey);
	intent.putExtra(Widget.Intents.EXTRA_AHA_PACKAGE_NAME, mHostAppPackageName);
	intent.putExtra(Widget.Intents.EXTRA_INSTANCE_ID, mInstanceId);

	intent.setPackage(mContext.getPackageName());
	//TODO
	// 1つのアプリで複数のウィジェットを自動更新できるようにする対応
	// これを入れないと,PendingIntentが後勝ちになって,1つのウィジェットにしか更新リクエストが飛ばない
	PendingIntent pi = PendingIntent.getBroadcast(mContext, mInstanceId, intent,
			PendingIntent.FLAG_CANCEL_CURRENT);
	return pi;
}
ソースが公開されているのはありがたい...

参考

問題点 その2 (proguard)

proguardですが,特に設定せずにかけると,ウィジェットとして認識されなくなります.

ウィジェット実装クラスは,SDKの方でリフレクション経由でインスタンス生成されているため, コンストラクタが未使用メソッドとしてproguardに除去されてしまうのが原因です.

それで,proguardの設定に以下の内容を追記して対応しました.

-keep class * extends com.sonyericsson.extras.liveware.extension.util.widget.BaseWidget {
 public <init>(com.sonyericsson.extras.liveware.extension.util.widget.BaseWidget$WidgetBundle);
}
ウィジェット実装クラス(=BaseWidget派生クラス)のコンストラクタを,keepするように設定します.

問題点 その3 (盤面更新の安定性)

上のプログラムでは,コンテンツの更新をsendText()を使って
@Override
public void onScheduledRefresh() {
	// コンテンツの定期更新
	sendText(R.id.txt, "〜");
}
と書いていますが,どうもこの方法は不安定でした.

ある程度時間がたつか何らかのきっかけで,そのウィジェットの盤面での表示が更新されなくなるという現象が発生しました. sendText()を実行しているのに,表示が更新されないのです.

以下のように,sendText()ではなくshowLayout()を使った方が安定している感じです.

// コンテンツの定期更新
Bundle bundle = new Bundle();
bundle.putInt(Widget.Intents.EXTRA_LAYOUT_REFERENCE, R.id.txt);
bundle.putString(Control.Intents.EXTRA_TEXT, "〜");
Bundle[] layoutData = new Bundle[1];
layoutData[0] = bundle;
showLayout(R.layout.mywidget, layoutData);
kamolandをフォローしましょう


© 2017 KMIソフトウェア