Tuesday, March 31, 2020

Liferay DXP 7.1 言語リソースカスタマイズの共有

こんにちは、うです。

前回、Liferay DXP 7でのカスタイムモジュール(ポートレット)の言語リソースを他モジュールに共有する方法を紹介しました。今回は、Liferay DXP 7.1以降、既存モジュール言語リソースに対するカスタマイズを複数既存モジュールに適用する方法を紹介します。

みなさまはすでにご存知かもしれませんが、Liferay DXP 7.1から、モジュール言語リソースのカスタマイズ方式は従来のOSGI-Service方式からOSGI-Capability方式になりました。従って、bnd-tools Provide-Capabilityのみで、複数モジュールが同じ言語リソースカスタマイズを利用できます。

公式例:
Provide-Capability:\
  liferay.resource.bundle;\
    resource.bundle.base.name="content.Language",\
  liferay.resource.bundle;\
    resource.bundle.aggregate:String="(bundle.symbolic.name=com.liferay.docs.l10n.myapp.lang),\
      (bundle.symbolic.name=com.liferay.blogs.web)";\
    bundle.symbolic.name=com.liferay.blogs.web;\
    resource.bundle.base.name="content.Language";\
    service.ranking:Long="2";\
    servlet.context.name=blogs-web

複数カスタマイズ共有(例として、blogs-webproduct-navigbation-control-menu-webを対象にする)例。

Provide-Capability:\
  liferay.resource.bundle;\
    resource.bundle.base.name="content.Language",\
  liferay.resource.bundle;\
    resource.bundle.aggregate:String="(bundle.symbolic.name=com.liferay.docs.l10n.myapp.lang),\
      (bundle.symbolic.name=com.liferay.blogs.web)";\
    bundle.symbolic.name=com.liferay.blogs.web;\
    resource.bundle.base.name="content.Language";\
    service.ranking:Long="2";\
    servlet.context.name=blogs-web
  liferay.resource.bundle;\
    resource.bundle.aggregate:String="(bundle.symbolic.name=com.liferay.docs.l10n.myapp.lang),\
      (bundle.symbolic.name=com.liferay.product.navigation.control.menu.web)";\
    bundle.symbolic.name=com.liferay.product.navigation.control.menu.web;\
    resource.bundle.base.name="content.Language";\
    service.ranking:Long="2";\
    servlet.context.name=product-navigation-control-menu-web

まとめると、Liferay DXP 7.1にでの言語リソース定義は、以下のルールに従いましょう。

  •  bnd.bndProvide-Capabilityを追加する
  •  Provide-Capabilityに以下のディレクティブを追加する
    1. liferay.resource.bundle;resource.bundle.base.name=...: 言語キー所在パッケージパスを定義する
    2. liferay.resource.bundle;resource.bundle.aggregate...: カスタム対象モジュールを宣言する
    3. 複数の対象モジュールがある場合、上記2のディレクテイブを複数記入する
    4. 全てディレクテイブはコンマ,で区切る

Alfresco Community Edition 201911GAをDocker Composeでデプロイする

こんにちは。てらしたです。前回投稿したのがいつだったのか思い出せないくらい久しぶりですが、これからまた少しずつ書いていけたらと思っています。

今回は、Alfresco Community EditionをDocker Composeを使用してデプロイする方法をご紹介します。Alfrescoがどういうものなのかちょっと使って評価してみたいという場合には、とても簡単にできるのでおすすめです(ただし、本番で使う場合にはDocker Composeは推奨されていません)。
使用するバージョンは現時点(2020年3月)での最新のGA版であるAlfresco Community Edition 201911 GAです。リリースノートはこちら。AlfrescoやShareの6.2.0が含まれています。
手順については以前ニコラが紹介したこちらの内容からほとんど変わっていませんが、Alfresco Platformにもポート8080でアクセスできる点等、ちょっとした違いがあります。
また、基本的には公式ドキュメント(https://docs.alfresco.com/community/tasks/deploy-docker-compose.html)の手順どおりですが、URLにバージョンが含まれていないことからもわかるように、Community版のドキュメントはその時点の最新版のGAのものしか公開されていないようです(私が見つけられないだけかもしれませんが...)。そのため、上記の公式ドキュメントは現時点では201911GAの内容が書かれていますが、新しいバージョンがリリースされたら更新されて下記でご紹介する手順から変わってしまう可能性があります。下記の内容は201911GAのデプロイ方法である点にご注意ください。

まず準備として、手元の環境に合わせてDockerとDocker Composeをインストールしておいてください。

次に、GitHubのプロジェクトをcloneして、201911GAに対応するタグ(3.0.1)をチェックアウトします。
git clone https://github.com/Alfresco/acs-community-deployment.git
cd acs-community-deployment
git checkout 3.0.1
あとは、Docker Composeを使用して起動するだけです。この時、ポート5432、8080、8083が空いている(使われていない)ことをあらかじめ確認しておいてください。
cd docker-compose
docker-compose up
特にエラーが出ることもなく以下のようなログが表示されたら無事に起動しているはずです(起動できない場合については後述)。
alfresco_1               | 17-Mar-2020 01:56:09.395 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 97601 ms

正常に起動しているかどうかはAlfresco Shareに以下のURLでアクセスして、adminでログインできるかどうかでも確認できます(adminの初期パスワードはadminです)。

http://localhost:8080/share

また、Alfresco PlatformやSolrには以下のURLでアクセスできます。

http://localhost:8080/alfresco
http://localhost:8083/solr

正常に起動できない場合は、Dockerに割り当てているメモリが不足している可能性があります(私も一度それで失敗しました)。Dockerの設定で最低でも6GBのメモリを割り当てた上で改めて試してみてください。

Tuesday, March 17, 2020

Liferay DXP 7でツールチップとヘルプアイコンを実装する

こんにちは。おおたにです。

今回はツールチップとヘルプアイコンの実装方法について紹介します。
ツールチップと言えば、以下のようなやつですね。ちょっとした説明をポップアップ表示させられるのでなかなか便利です。


Liferayでは、ヘルプアイコンとセットになったツールチップ(上の画像のやつ)の部品が用意されているほか、任意のHTML要素へのツールチップ追加も簡単にできます。それぞれについて見ていきましょう。

ヘルプアイコン


ヘルプアイコンの表示にはliferay-ui:icon-helpというタグを使います。例えばこんな感じに書くだけで、

<p>help icon 2<liferay-ui:icon-help message="msg.tooltip.help-icon"/></p>

以下のようなヘルプアイコン&ツールチップが実装できます。messageに言語キーを指定すると多言語化もできます。超簡単!


Liferay Development Tutorialsに詳しい説明が載っていますのでご参照ください。

任意のHTML要素へのツールチップ追加


HTML要素のclass属性にlfr-portal-tooltipを追加し、data-title属性にツールチップの文言を指定するだけで、任意のHTML要素にツールチップを追加できます。例えば、

<p class="lfr-portal-tooltip" data-title="tooltip for html element">html element 1</p>

と書くだけで、以下のようなツールチップが表示されるようになります。こちらも簡単!


こちらを多言語化する場合は、JSP式(JSP expression)等を使ってdata-title属性に多言語化された文字列を指定する必要があります。

data-title="<%=LanguageUtil.get(request, "msg.tooltip.html-element") %>"

今回は以上になります。是非みなさんもツールチップを使ってみてください!

Tuesday, March 3, 2020

Liferay DXP 7でカスタムモジュールの言語リソースを共有する

こんにちは。おおたにです。 

突然ですが、Liferay DXP 7のカスタマイズを進める中で、「前に作ったモジュールの言語リソースをこちらでも使いたいな」とか「言語リソースの定義が複数のモジュールに散らばっていて管理しずらいな」と感じたことはありませんでしょうか?
今回は、上記のようなシチュエーションで役立つ、カスタムモジュールの言語リソースを共有するための方法を紹介します。

方法はとてもシンプルで、モジュールのbnd.bndに以下の内容を追記すると、他のモジュールで定義された言語リソースを参照できるというものです。
-liferay-aggregate-resource-bundles: \
    <参照したい言語リソースを持つモジュールのSymbolicName>

例えば、言語リソース一元管理用のモジュールを用意して各モジュールから参照させることで、言語リソースの管理コストや言語リソース更新し忘れによる表記揺れのリスクを低減することができます。
詳しくはこちらのドキュメントこちらのドキュメントをご参照ください。Liferay社が提供するサンプルも参考になりますので是非一度確認してみてください。

Wednesday, June 19, 2019

Liferayモバイルアプリにプッシュ通知を実装する

こんにちは。おおたにです。

今回は、Liferayモバイルアプリへのプッシュ通知組み込みについて紹介します。Liferayのモバイル対応については別の記事「Liferay Screensでモバイルアプリを作ってみよう(初級編)」「Liferay Screensでモバイルアプリを作ってみよう(ログイン画面実装編)」で紹介していますが、今回はLiferay Screensを使って開発したAndroidアプリにプッシュ通知機能を実装してみようと思います。

必要なもの


モバイルへのプッシュ通知を実現するためには、以下の3つが必要です。
  1. プッシュ通知サービスの設定
    • Android : Firebase Cloud Messaging(FCM)
    • iOS : Apple Push Notification Service(APNS)
  2. モバイルアプリのプッシュ通知対応
  3. プッシュ通知を管理するアプリケーション
    • インストールされたモバイルアプリのデバイストークンの収集
    • プッシュ通知の内容と配信先の管理
    • プッシュ通知の配信(正確にはプッシュ通知サービスへの配信依頼)
今回は3.としてLiferay PushプラグインをインストールしたLiferayを利用します。このプラグインはEnterprise Edition(Liferay DXP)専用ですので、Community Edition(Liferay Portal CE)をお使いの方は、Amazon Simple Notification Service(SNS)等を利用してプッシュ通知管理アプリを開発するか、モバイル組み込みに対応したサードパーティのプッシュ通知配信サービスを利用する必要があります。

では、実際の実装について見ていきましょう。

プッシュ通知サービスの設定


今回はAndroidアプリにプッシュ通知を送信するため、Firebase Cloud Messaging(FCM)を利用します。まずはFirebaseの設定から行います。

1. Firebaseコンソールにログインする

2. 「新しいプロジェクト」をクリックし、プロジェクト名等を適当に入力してプロジェクトを作成する

3. 「開始するにはアプリを追加してください」のAndroidアイコンをクリックし、Androidアプリのパッケージ名(アプリケーションID)を入力してアプリを登録します。詳細な手順はFirebaseのドキュメントに記載されています。登録の後、以下の情報をコピーしておきます。
  • google-services.json
  • 登録したアプリのクラウドメッセージングのサーバーキーと送信者ID

モバイルアプリのプッシュ通知対応


続いて、モバイルアプリにプッシュ通知の対応を実装します。まずは「Liferay Screensでモバイルアプリを作ってみよう(ログイン画面実装編)」でLiferay Screensを使ったアプリを開発し、追加で以下の実装を行います。

1. Androidプロジェクトの app フォルダに google-services.json をコピーする

2. プロジェクトルートの build.gradle に以下のclasspathを追加する
buildscript {
 ...
 dependencies {
  ...
  classpath 'com.google.gms:google-services:4.2.0'
 }
}

3. app フォルダの build.gradle の最後に以下の行を追加する
apply plugin: 'com.google.gms.google-services'

4. app フォルダの build.gradle に以下のimplementationを追加し、画面上部に表示されるSync Nowをクリックする
apply plugin: 'com.android.application'
...
dependencies {
 ...
 implementation 'com.google.firebase:firebase-messaging:17.6.0'
}

5. AndroidManifest.xml に以下の内容を追加する
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>

<receiver
    android:name=".PushReceiver"
    android:permission="com.google.android.c2dm.permission.SEND">
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
        <category android:name="com.liferay.mobile.push"/>
    </intent-filter>
</receiver>

<service android:name=".PushService"/>

<meta-data
    android:name="com.google.firebase.messaging.default_notification_channel_id"
    android:value="@string/fcm_fallback_notification_channel_label" />

6. res/values/strings.xml に以下の行を追加する
<string name="fcm_sender_id">FCMでコピーした送信者ID</string>

7. MainActiity.java のベースクラスを AppCompatActivity から PushScreensActivity に変更し、以下の実装を追加する
@Override
protected Session getDefaultSession() {
   return SessionContext.createSessionFromCurrentSession();
}

@Override
protected void onPushNotificationReceived(final JSONObject jsonObject) {
   LiferayLogger.i("Push notification received: " + jsonObject.toString());
}

@Override
protected void onErrorRegisteringPush(final String message, final Exception e) {
   // Do nothing
}

@Override
protected String getSenderId() {
   return getResources().getString(R.string.fcm_sender_id);
}

8. MainActiity.java の onCreate の実装を以下のように変更する(loadStoredCredentialsAndServerの後にベースクラスのonCreateを呼ぶのがポイントです)
public void onCreate(Bundle savedInstanceState) {
    SessionContext.loadStoredCredentialsAndServer(CredentialsStorageBuilder.StorageType.SHARED_PREFERENCES);
    super.onCreate(savedInstanceState);
    if (!SessionContext.isLoggedIn()) {
        startActivity(new Intent(getApplication(), LoginActivity.class));
    } else {
        setContentView(R.layout.activity_main);
        WebScreenlet screenlet = findViewById(R.id.web_screenlet);
        screenlet.setListener(this);
        WebScreenletConfiguration webScreenConfiguration = new WebScreenletConfiguration.Builder(LiferayServerContext.getServer() + "/web/guest/home")
                .setWebType(WebScreenletConfiguration.WebType.LIFERAY_AUTHENTICATED).load();
        screenlet.setWebScreenletConfiguration(webScreenConfiguration);
        screenlet.load();
        LiferayLogger.i("##### device token : " + FirebaseInstanceId.getInstance().getToken());
    }
}

9. PushService.java を MainActivity.java と同じフォルダに作成し、以下のとおり実装する(プッシュ通知受信時の処理として、Androidの通知エリアに通知を表示する処理を実装しています)
public class PushService extends AbstractPushService {
    @Override
    protected void processJSONNotification(JSONObject json) throws JSONException {
        NotificationCompat.Builder builder;
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String channelId = getResources().getString(R.string.fcm_fallback_notification_channel_label);
            if (notificationManager.getNotificationChannel(channelId) == null) {
                notificationManager.createNotificationChannel(new NotificationChannel(channelId, channelId, NotificationManager.IMPORTANCE_HIGH));
            }
            builder =  new NotificationCompat.Builder(this, channelId);
        } else {
            builder = new NotificationCompat.Builder(this);
        }
        builder.setContentTitle(getString(json, "title"))
                .setContentText(getString(json, "body"))
                .setAutoCancel(true)
                .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
                .setSmallIcon(R.drawable.liferay_glyph)
                .setPriority(Notification.PRIORITY_HIGH);
        notificationManager.notify(1, builder.build());
    }

    private String getString(final JSONObject json, final String element) throws JSONException {
        return json.has(element) ? json.getString(element) : "";
    }
}

10. PushReceiver.java を MainActivity.java と同じフォルダに作成し、以下のとおり実装する
public class PushReceiver extends AbstractPushReceiver {
    @NonNull
    @Override
    protected Class getPushServiceClass() {
        return PushService.class;
    }
}

ビルドに失敗する場合は、依存するライブラリのバージョン齟齬等を確認してください。sdkVersionやdependencies内のライブラリバージョンを変更する等の対応が必要なことがあるかもしれません。

Liferay Pushの設定


最後に、Liferay側の設定を行います。設定自体はいたってシンプルです。

1. Liferay MarketplaceからLiferay Pushをダウンロードし、ファイルをLiferayの deploy フォルダにコピーしてインストールする

2. インストール完了後、Liferayを再起動する

3. 管理者としてLiferayにログインし、Control Panel -> Configuration -> System Settings -> Platform -> Notifications -> Android のAPI Key欄に、FCMでコピーしたサーバーキーを入力してUpdateをクリックする

テストしてみよう


では、実際にテストしてみましょう。テストの手順は以下のとおりです。

1. モバイルアプリを起動し、Liferayにログインする

2. 管理者としてブラウザでLiferayのにログインし、Control Panel -> Configuration -> Push Notifications -> Devices に、モバイルアプリにログインしたユーザ名と併せてデバイストークン/Platform(今回はAndroid)が記録されていることを確認する(アプリ側でデバイストークンをログ出力する等しておくと確認しやすい)

3. Testタブに移動し、Message欄にプッシュ通知のペイロードをJSON形式で入力してSendをクリックする(今回はモバイルアプリ側でtitleとbodyを表示するよう実装したので、以下のようなプッシュ通知ペイロードを指定する)
{
  "title": "プッシュ通知テスト",
  "body": "これはプッシュ通知のテストです。"
}

4. Android端末側でプッシュ通知を受信したことを確認する(今回のサンプルコードではAndroidの通知エリアに通知が表示されます)


今回の紹介は以上になります。実用的なプッシュ通知の実装には、モバイルアプリのバックグラウンド/フォアグラウンドの判定や、それに応じてプッシュ通知の通知方法を変えるなどの考慮が必要ですが、エッセンシャルな部分は上記記事の内容でカバーできているかと思います。
また、実際にプッシュ通知を配信するためには PushNotificationsDeviceLocalService を利用する必要がありますので、こちらのドキュメントを参考にしてください。

Tuesday, June 4, 2019

Liferay Screensでモバイルアプリを作ってみよう(ログイン画面実装編)

こんにちは。おおたにです。

以前、Liferay Screensでモバイルアプリを作ってみよう(初級編)という記事を書きましたが、今回はアプリにログイン画面の機能を追加してみようと思います。以下ではこの記事のアプリに追加の機能を実装していくため、まずは上記記事を参考にアプリを作成してください。

Liferay ScreensのScreenletを探す


上記記事で、Screenletと呼ばれる出来合いのコンポーネントが提供されていることをお話ししました。Android向けiOS向けに多数のコンポーネントがあるので、まずは目的の機能がScreenletとして提供されているか探します。今回はLogin Screenletという部品が目的にマッチするので、これを使って実装します。


Login Screenletを組み込む


さて、利用する部品が決まったので早速組み込みます。既存のactivityにログイン処理を追加することもできますが、今回はログイン処理用に新しいactivityを追加します。

1. Androidプロジェクト上で新規Empty Activityを追加する。Activity NameをLoginActivity、Layout Nameをactivity_loginとしておきます。

2. AndroidManifest.xmlapplicationタグに.LoginActivityのエントリが生成されているので、その内容を以下のように書き換える。
<activity
    android:name=".LoginActivity"
    android:label="@string/activity_name"
    android:theme="@style/AppTheme">
</activity>

3 Androidプロジェクトのres/layout/activity_login.xmlを以下の内容で書き換え、Login Screenletをレイアウトに挿入する。これがログイン画面になります。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.liferay.mobile.screens.auth.login.LoginScreenlet
        android:id="@+id/login_screenlet"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:basicAuthMethod="email"
        app:credentialsStorage="shared_preferences"
        app:loginMode="basic" />
</LinearLayout>

4. LoginActivity.javaを以下の内容に置き換え、LoginListenerを実装する。ログイン画面の表示と、ログイン成功時にMainActivityに遷移する部分がポイントです。
public class LoginActivity extends AppCompatActivity implements LoginListener {

    private View content;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        LoginScreenlet screenlet = findViewById(R.id.login_screenlet);
        screenlet.setListener(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        content = findViewById(android.R.id.content);
    }

    @Override
    public void onLoginSuccess(User user) {
        startActivity(new Intent(getApplication(), MainActivity.class));
    }

    @Override
    public void onLoginFailure(Exception e) {
        Toast.makeText(this, R.string.login_error, Toast.LENGTH_SHORT).show();
    }
}

5. MainActivity.javaonCreateを以下の内容に変更し、未ログイン時にLoginActivity(ログイン画面)に遷移する処理を追加する。
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    WebScreenlet screenlet = findViewById(R.id.web_screenlet);
    screenlet.setListener(this);

    SessionContext.loadStoredCredentialsAndServer(CredentialsStorageBuilder.StorageType.SHARED_PREFERENCES);
    if (!SessionContext.isLoggedIn()) {
        startActivity(new Intent(getApplication(), LoginActivity.class));
    } else {
        WebScreenletConfiguration webScreenConfiguration = new WebScreenletConfiguration.Builder(LiferayServerContext.getServer() + "/web/guest/home")
                .setWebType(WebScreenletConfiguration.WebType.LIFERAY_AUTHENTICATED).load();
        screenlet.setWebScreenletConfiguration(webScreenConfiguration);
        screenlet.load();
    }
}

以上でログイン画面の実装は終わりです。とても簡単ですね!


エミュレータで動作確認してみよう


では、動作確認をしてみましょう。DebugもしくはRunアイコンをクリックし、Virtual Deviceを選択してエミュレーション開始です(Virtual Deviceが無い場合はCreate New Virtual Deviceで作成してください)。ビルドに成功すれば以下のようなログイン画面が表示されるはずです。


ユーザIDとパスワードを入力してログインに成功するとLiferayサイトが表示されるはずです。ログインに失敗した場合はログイン失敗メッセージが表示されてログイン画面に戻ります。

ログイン画面の実装は以上です。専用のログイン画面を用意するだけで、ぐっとネイティブアプリ感が出てくるうえに、認証情報/セッション情報をAndroid側で保持することもできるようになります。是非みなさんもチャレンジしてみてください!

Wednesday, May 15, 2019

Liferay Screensでモバイルアプリを作ってみよう(初級編)

こんにちは。おおたにです。

今回は、Liferay DXPのモバイル対応について紹介したいと思います。

まず、Liferayで構築したWebサイトはレスポンシブなデザインとなっているため、スマートフォン等のブラウザからアクセスすれば画面サイズに応じた適切な見栄えで表示されます。なので、ブラウザからのアクセスが許容されるのであれば、モバイル対応に際して本記事にあるような開発は一切必要ありません。

Liferay Mobile SDKとLiferay Screens


一方で、専用のモバイルアプリを開発するとなると、Liferayで構築したWebサイトにモバイルアプリからアクセスする、もしくはモバイルアプリがLiferayの提供するサービスをバックエンドで利用するようなケースに対して、Liferayは以下の2つの機能を提供しています。

Liferay Mobile SDK

Mobile SDKは、Liferayの認証や権限解決、Webサービス呼出等の機能をネイティブモバイルアプリに提供するものです。Liferayが提供する機能はほぼ全てWeb APIとして提供されているため、HTTPリクエストレベルの記述を行えば何でも実装できるのですが、Mobile SDKはLiferayとの通信をラップして各機能を簡単に利用できるようにしています。モバイルアプリの認証基盤としてLiferayを利用したい、バックエンドでLiferayのサービス(カスタムサービス含む)にアクセスしたいというような、独自のモバイルアプリにLiferayのローレベルの(APIレベルの)機能を組み込むケースに適しています。

Liferay Screens

Screensは、Liferayの種々の機能を出来合いのコンポーネントとして提供するものです。このコンポーネントはScreenletと呼ばれ、Android向けiOS向けにそれぞれ多数のコンポーネントが提供されています。ログイン画面やWebコンテンツ表示、アセット表示などのハイレベルの機能が、Liferayとの通信だけでなくモバイルアプリのUIも含めて提供されているため、これら出来合いのコンポーネントを組み合わせるだけで簡単にモバイルアプリを開発することができます。提供されているScreenletである程度要件を満たせるケースであれば利用の価値があります。

モバイルアプリを作ってみよう


というわけで、さっそくモバイルアプリを作ってみましょう!以下、Cordova + Liferay ScreensでシンプルなAndroidアプリを開発していきます。Cordovaを使う理由は、Cordovaプラグインを利用できるようにするところにあります。Cordovaと聞くとクロスプラットフォームも期待してしまいますが、Liferay Screensとの組み合わせだとその限りではありません。残念…
なお、今回はWeb Screenletというコンポーネントを使ってWebページをそのまま埋め込み表示してみます。いわゆるWebViewですね。

事前準備

まずは開発に必要なツール類をインストールします。

1. gitのサイトからインストーラをダウンロードし、gitをインストールする。

2. Node.jsのサイトからインストーラをダウンロードし、Node.jsをインストールする。

3. 以下のコマンドを実行し、Apache Cordovaをインストールする。
$ npm install -g cordova

4. 以下のコマンドで screens-cli をインストールする。
$ npm install -g screens-cli

5. こちらのサイトを参考にしてAndroid Studioをインストールする。

6. こちらの記事を参考にしてAndroidエミュレータをセットアップする。

プロジェクトの作成

以下、Liferay Developer Networkのドキュメントに従って進めます。

1. プロジェクト用のフォルダを作成する。
$ mkdir <プロジェクト名>
$ cd <プロジェクト名>

2. 上記フォルダにファイル.plugins.screensを作成し、利用したいCordovaプラグイン名を列挙する
cordova-plugin-call-number
cordova-plugin-camera

3. 以下のコマンドを実行してプロジェクトを作成する
$ screens-cli android <プロジェクト名>

4. 成功するとフォルダ <プロジェクト名>/platform/android/<プロジェクト名> をAndroid Studioで開けるようになるので、Android Studioを起動してこのフォルダを開く

5. Android Studioで Failed to find target with hash string 'android-xx' エラーが出る場合は、SDK Managerアイコンをクリックして当該バージョンにチェックを入れ、必要なバージョンのSDKをインストールする。


5. 改めてFile -> Sync Project with Gradle Filesをクリックする。適宜必要なツールをインストールしてビルドが通るようになることを確認する。

Web Screenletの組み込み

続いて、Web Screenletを組み込みます。Liferay Developer Networkのこちらこちらの記事が参考になると思います。

6. Androidプロジェクトのres/valuesフォルダにファイルserver_context.xmlを作成し以下の内容を入力する。各値は環境にあった内容に変更する。
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="liferay_server">http://10.0.2.2:8080</string>
    <integer name="liferay_portal_version">71</integer>
    <string name="liferay_company_id">20099</string>
</resources>
  • liferay_server : LiferayサーバのURL(10.0.2.2はエミュレータから見た時のローカルホストのIP)
  • liferay_portal_version : Liferayバージョン(Liferay7の場合は70、Liferay7.1の場合は71)
  • liferay_company_id : アクセス先のインスタンスID(Liferayのメニュー->コントロールパネル->設定->仮想インスタンス->インスタンスIDで確認する)

7. AndroidManifest.xmlapplicationタグに属性android:usesCleartextTraffic="true"を追加し(LiferayサーバURLがHTTPの場合にエラーが発生するのを防ぐため)、activityタグの属性android:themeの値を"@style/AppTheme"に変更する。
<application .... android:usesCleartextTraffic="true">
    <activity .... android:name="MainActivity" android:theme="@style/AppTheme" ....>

8. Androidプロジェクトのres/values/styles.xmlを開き、AppThemeの親テーマを以下のように変える
<style name="AppTheme" parent="default_theme">

9. Androidプロジェクトのres/layout/actiity_main.xmlに以下のスニペットを挿入し、Web Screenletを追加する。
<com.liferay.mobile.screens.web.WebScreenlet
  android:id="@+id/web_screenlet"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:layoutId="@layout/web_default"
  app:autoLoad="false"
/>

10. MainActivity.javaを以下の内容に置き換え、WebListenerを実装する。
public class MainActivity extends AppCompatActivity implements WebListener {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    WebScreenlet screenlet = (WebScreenlet)findViewById(R.id.web_screenlet);
    screenlet.setListener(this);
    WebScreenletConfiguration webScreenConfiguration = new WebScreenletConfiguration.Builder("/web/guest/home")
        .setWebType(WebScreenletConfiguration.WebType.OTHER).load();
    screenlet.setWebScreenletConfiguration(webScreenConfiguration);
    screenlet.load();
  }

  @Override
  public void onPageLoaded(String url) {
    Toast.makeText(this, "Page load successful!", Toast.LENGTH_SHORT).show();
  }
  
  @Override
  public void onScriptMessageHandler(String namespace, String body) {
    // do nothing
  }

  @Override
  public void error(Exception e, String userAction) {
    Toast.makeText(this, "Bad things happened: " + e.getMessage(), Toast.LENGTH_LONG).show();
  }
}

以上でWeb Screenletの埋め込みの完了です。

エミュレータで動作確認してみよう


では、さっそく動作確認してみましょう。DebugもしくはRunアイコンをクリックし、Virtual Deviceを選択してエミュレーション開始です(Virtual Deviceが無い場合はCreate New Virtual Deviceで作成してください)。


ビルドに成功すると、以下のようにエミュレータが起動してモバイルアプリが自動で立ち上がり、Liferayサイトが表示されます。


以上でWeb Screenletを使ったシンプルなAndroidアプリができました。とても簡単!
これをベースに色々な機能を追加していくことができます。例えば、ネイティブアプリとしてログイン画面を提供したり、他のScreenletを使う、Cordovaプラグインを使うなどがあると思いますが、これらの方法についてはまた別の機会に紹介したいと思います。みなさんも是非モバイルアプリの開発にチャレンジしてみてください!