20200824のAndroidに関する記事は9件です。

HUAWEI ML Kitでフェースステッカーをアプリに組み込む方法

概要

今では、かわいく、おもしろいフェースステッカーをどこでも見るようになりました。カメラアプリだけでなく、ソーシャルメディアやエンタテイメントのアプリでも使用されています。今回の投稿では、HUAWEI ML Kitを使用して2Dステッカーを作成する方法をご紹介します。近いうちに、3Dステッカーの開発プロセスをお知らせしますので、ご期待ください。

シナリオ

ビューティカメラやソーシャルメディアアプリ(TikTok、Weibo、WeChatなど)など、写真を撮影して編集する場合に使用するアプリは、画像のカスタマイズに使用できる幅広いステッカーを用意しています。このようなステッカーを使って、ユーザーはより人目を引き、共有できるコンテンツを作成できます。

準備

Huawei Mavenリポジトリをプロジェクトレベルのbuild.gradleファイルに追加する

Android Studioプロジェクトのルートディレクトリにあるbuild.gradleファイルを開きます。
2.1.png
Mavenリポジトリアドレスを追加します。

buildscript {
     {        
        maven {url 'http://developer.huawei.com/repo/'}
    }    
}
allprojects {
    repositories {       
        maven { url 'http://developer.huawei.com/repo/'}
    }
}

SDK依存関係をアプリレベルのbuild.gradleファイルに追加する

2.2.png

// Face detection SDK.
implementation 'com.huawei.hms:ml-computer-vision-face:2.0.1.300'
// Face detection model.
implementation 'com.huawei.hms:ml-computer-vision-face-shape-point-model:2.0.1.300'

AndroidManifest.xmlファイルでカメラ、ネットワークアクセス、およびストレージの権限を適用する

<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

コードの開発

顔分析機能を設定する

顔の輪郭ポイントを取得し、FacePointEngineに渡す

MLFaceAnalyzerSetting detectorOptions;
detectorOptions = new MLFaceAnalyzerSetting.Factory()
        .setFeatureType(MLFaceAnalyzerSetting.TYPE_UNSUPPORT_FEATURES)
        .setShapeType(MLFaceAnalyzerSetting.TYPE_SHAPES)
        .allowTracing(MLFaceAnalyzerSetting.MODE_TRACING_FAST)
        .create();
detector = MLAnalyzerFactory.getInstance().getFaceAnalyzer(detectorOptions);

カメラのコールバックを使用してカメラのフレームデータを取得し、顔分析機能を呼び出して顔の輪郭ポイントを取得し、FacePointEngineに渡します。これにより、ステッカーフィルタはポイントを後で利用できます。

@Override
public void onPreviewFrame(final byte[] imgData, final Camera camera) {
    int width = mPreviewWidth;
    int height = mPreviewHeight;

    long startTime = System.currentTimeMillis();

    if (isFrontCamera()){
        mOrientation = 0;
    }else {
        mOrientation = 2;
    }
    MLFrame.Property property =
            new MLFrame.Property.Creator()
                    .setFormatType(ImageFormat.NV21)
                    .setWidth(width)
                    .setHeight(height)
                    .setQuadrant(mOrientation)
                    .create();

    ByteBuffer data = ByteBuffer.wrap(imgData);

    SparseArray<MLFace> faces = detector.analyseFrame(MLFrame.fromByteBuffer(data,property));

    if(faces.size()>0){
        MLFace mLFace = faces.get(0);
        EGLFace EGLFace = FacePointEngine.getInstance().getOneFace(0);
        EGLFace.pitch = mLFace.getRotationAngleX();
        EGLFace.yaw = mLFace.getRotationAngleY();
        EGLFace.roll = mLFace.getRotationAngleZ() - 90;
        if (isFrontCamera())
            EGLFace.roll = -EGLFace.roll;
        if (EGLFace.vertexPoints == null) {
            EGLFace.vertexPoints = new PointF[131];
        }
        int index = 0;

        for (MLFaceShape contour : mLFace.getFaceShapeList()) {
            if (contour == null) {
                continue;
            }
            List<MLPosition> points = contour.getPoints();

            for (int i = 0; i < points.size(); i++) {
                MLPosition point = points.get(i);
                float x = ( point.getY() / height) * 2 - 1;
                float y = ( point.getX() / width ) * 2 - 1;
                if (isFrontCamera())
                    x = -x;
                PointF Point = new PointF(x,y);
                EGLFace.vertexPoints[index] = Point;
                index++;
            }
        }

        FacePointEngine.getInstance().putOneFace(0, EGLFace);

        FacePointEngine.getInstance().setFaceSize(faces!= null ? faces.size() : 0);
    }else{
        FacePointEngine.getInstance().clearAll();
    }
    long endTime = System.currentTimeMillis();
    Log.d("TAG","Face detect time: " + String.valueOf(endTime - startTime));
}

ML Kit APIが返す顔の輪郭ポイントは下記の画像で確認できます。
2.jpg

ステッカーのJSONデータの定義

猫のステッカーを作る

猫のステッカーのJSONファイルを作成し、フェースインデックスを使用して眉毛(84)の間の中心点と鼻(85)の先端の点を見つけます。猫の耳と鼻をペーストし、JSONファイルと画像をassetsディレクトリに置きます。

ステッカーをレンダリングして質感を与える

GLSurfaceViewを使用してステッカーをレンダリングして質感を与えます。これは、TextureViewを使用するより簡単です。onSurfaceChangedでステッカーフィルタのインスタンスを作成し、ステッカーのパスを渡してカメラを開始します。

onSurfaceChangedでステッカーフィルタを初期化する

onDrawFrameで画面にステッカーを描画する

以上で終わりです。作成したフェースステッカーは使用可能です。
早速、使ってみましょう。
20200820-201607(eSpace).gif
詳しくは、当社の公式ウェブサイトをご覧ください。
当社のデモコードもご覧ください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Flutter, Dart, freezed】Bad state: Unexpected diagnosticsでbuildが終わらない不具合

TL;DR

pubspec.yaml に以下の2つを追加してください

pubspec.yaml
dependencies:
  analyzer: ^0.39.14 <- 追加

dev_dependencies:
  build_runner: ^1.10.0 <- 追加

環境

# fvmを使用
[✓] Flutter (Channel unknown, 1.20.2, on Mac OS X 10.15.5 19F101, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.6)
[✓] Android Studio (version 4.0)

症状

  • Bad state: Unexpected diagnostics: が大量に表示される
  • [INFO] 1.6s elapsed, 1/12 actions completed. が永遠に完了しない
$ fvm flutter packages pub run build_runner build --delete-conflicting-outputs

[...]

[INFO] Running build...
[INFO] Generating SDK summary...
[SEVERE] freezed:freezed on test/widget_test.dart:

Bad state: Unexpected diagnostics:
/Users/k3ntar0/fvm/versions/1.20.2/bin/cache/dart-sdk/lib/core/uri.dart:3259:39 - Expected an identifier.
[SEVERE] freezed:freezed on test/widget_test.dart:

[...]

Bad state: Unexpected diagnostics:
/Users/k3ntar0/fvm/versions/1.20.2/bin/cache/dart-sdk/lib/core/uri.dart:3259:39 - Expected an identifier.
[INFO] 1.6s elapsed, 1/12 actions completed.
[INFO] 2.6s elapsed, 1/12 actions completed.
[INFO] 3.7s elapsed, 1/12 actions completed.
[INFO] 4.7s elapsed, 1/12 actions completed.
[INFO] 5.8s elapsed, 1/12 actions completed.
[INFO] 6.9s elapsed, 1/12 actions completed.
[INFO] 8.0s elapsed, 1/12 actions completed.
[INFO] 9.0s elapsed, 1/12 actions completed.
[INFO] 10.0s elapsed, 1/12 actions completed.
[INFO] 11.1s elapsed, 1/12 actions completed.
[INFO] 12.1s elapsed, 1/12 actions completed.
[INFO] 13.2s elapsed, 1/12 actions completed.
[INFO] 14.2s elapsed, 1/12 actions completed.
[INFO] 15.2s elapsed, 1/12 actions completed.
[WARNING] No actions completed for 15.1s, waiting on:
  - freezed:freezed on lib/main.dart
  - freezed:freezed on lib/app.dart
  - freezed:freezed on lib/presentation/common/colors.dart
  - freezed:freezed on lib/presentation/pages/home/home_page.dart
  - freezed:freezed on lib/presentation/pages/index.dart
  .. and 6 more

やること

  • pubspec.yaml を変更する
  • きれいにする
  • buildし直す

※ fvmを使用されていない場合はfvmの部分を消して実行してください

pubspec.yaml を変更する

pubspec.yaml
dependencies:
  analyzer: ^0.39.14 <- 追加

dev_dependencies:
  build_runner: ^1.10.0 <- 追加

きれいにする

# pubspec.lockを削除
$ rm -rf pubspec.lock

# clean
$ fvm flutter clean
Cleaning Xcode workspace...                                         2.9s
Deleting .dart_tool...                                               3ms
Deleting Generated.xcconfig...                                       0ms
Deleting flutter_export_environment.sh...                            0ms

buildし直す

# pub get
$ fvm flutter pub get
Running "flutter pub get" in my_project...                          2.5s

# build_runnerを実行
$ fvm flutter packages pub run build_runner build --delete-conflicting-outputs
Precompiling executable...
Precompiled build_runner:build_runner.
[INFO] Generating build script...

[...]

[INFO] Succeeded after 18.8s with 1 outputs (12 actions)

fvmを使用されていない場合は記述不要です!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[MVVM-DataBinding] 数字入力のEditTextに単位とセパレーターを自動で追加する

背景

数字入力に限定したEditText(android:inputType="number")に対して、3桁ごとのセパレーターとsuffixとして単位をつけたい

理由
・ユーザーに極力数字以外のものを受け付けたくない
・桁数と単位でより入力内容をわかりやすくしたい

環境

MVVM-DataBinding
※導入方法は省略

実装

今回は長さ(m)を例に実装します

やりたい事は、もしユーザーが1222と入力したとすると、1,222mEditTextに表示させたいです

XML

snippet.xml
<data>

    <import type="your.package.name.Converter" />

    <variable
        name="viewModel"
        type="your.package.name.SnippetViewModel" />
    </data>

(略)

<EditText
    android:id="@+id/length_m"
    android:layout_width="match_parent"
    android:gravity="end|center_vertical"
    android:hint="0m"
    android:inputType="number"
    android:maxLines="1"
    android:paddingStart="0dp"
    android:paddingEnd="8dp"
    android:text="@={Converter.addNumberSeparatorAndUnitMeter(viewModel.length)}"
    android:textSize="18sp" />

ViewModelbindingvariableとして登録
EditTextの内容を後述するMutableLiveDataと対応させたいので双方向データバインディングしています
Converterimportと使用、こちらも後述

ViewModel

SnippetViewModel.kt
class SnippetViewModel() : ViewModel() {

    val length = MutableLiveData<Int>()

()

ここでは対象のMutableLiveDataを定義しています

Converter

ここではEditText上でユーザーが数字が入力するものの、EditTextには数字+セパレーター+単位を表示したいわけです
ただし、今回は双方向データバインディングのため、またユーザーが数字を入力する際に、EditTextに表示されている数字+セパレーター+単位をそのままgetText等で使い数字のまま使えるわけではないので不整合が生じやすいです

そのため、
・EditTextへの入力内容(Int) -> EditTextの表示内容(String)
・EditTextの表示内容(String) -> EditTextの入力内容(Int)

これらをうまく変換するためのメソッドが必要になります
ここで役立つのが、@InverseMethodです

@InverseMethodでは上記の変換、逆変換をスマートにこなしてくれます
今回の例でいうとこのようになります

Converter.kt
object Converter {
    @InverseMethod("inverseToInt")
    @JvmStatic
    fun addNumberSeparatorAndUnitMeter(value: Int): String {
        val intValueWithFormat = String.format("%,d", value)
        return "${intValueWithFormat}m"
    }

    @JvmStatic
    fun inverseToInt(value: String?): Int {
        return kotlin.runCatching { value?.replace("m", "")?.replace(",", "")?.toInt() }
            .getOrNull() ?: 0
    }
}

ひとつめのaddNumberSeparatorAndUnitMeterではユーザーが入力した内容=LiveDataの値に対してセパレーターとmの単位を付与しています

@InverseMethod("inverseToInt")

inverseToIntは逆変換するのに必要なメソッド名になります
これにより再度ユーザーが数字を入力した際、逆変換のメソッドが呼ばれIntとなり、そのIntの値を使ってまたaddNumberSeparatorAndUnitMeterが呼ばれるということになります

inverseToIntメソッドでは数字+セパレーター+単位をIntに戻しています

これでユーザーが数字を入力するだけでEditTextにセパレーターと単位を補助入力できるようになりました?

InverseMethodを使うと何が嬉しいの?

個人的な意見です
・パターンに応じた複雑なロジックを自前で定義する手間が減る
・変換、逆変換の処理を無限ループしにくい状態で定義できる
・もとのLiveDataの値を変換していないままの型(今回はInt)として使うことができるので、その値を使ったバリデーションや値変換(Transformations.map)がしやすい

おわり

以上です 参考になれば幸いです
よりよい方法がありましたら是非ご教授ください?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HUAWEI ML Kitを使用した銀行カード認識の実装方法

概要

以前の投稿では、HUAWEI ML Kitを使用してSmile-CameraとID用写真のDIYアプレットを実装する方法について検討しました。今回の投稿では、銀行カード認識機能の実装方法をご紹介します。この機能により、ユーザーは銀行カードを瞬時に紐付けることができます。
1.png

銀行カード認識の用途

開発に着手する前に、銀行カード認識機能の用途について確認しましょう。銀行アプリやeコマースアプリなど、支払い機能を備えたアプリに最適です。このようなアプリには、いくつか共通の要件がある場合が多いです。

  • 銀行カードの紐付け

ユーザーは自分の銀行カードを紐付けて、オンライン決済を素早く行うことができます。

  • 銀行振込

ユーザーは同一銀行内または異なる銀行の口座間でお金を振り込むことができます。

  • 本名での認証とID確認

ユーザーは、自分の銀行カードに紐付けられた情報使用して、本名での認証とID確認を素早く実施できます。

このような機能ではそれぞれ、ユーザーはカード番号や有効期限など、銀行カード情報を入力する必要があります。当然、このような情報を手入力するのは時間がかかり、誤入力も発生しやすくなります。しかし、HUAWEI ML Kitの銀行カード認識サービスにより、ユーザーは情報を簡単かつ正確に入力できます。

銀行認識サービスの利用方法

銀行カード認識サービスは、カメラストリームで銀行カードを認識し、カード番号や有効期限など重要な情報を抽出します。このサービスはIDカード認識サービスと連携しており、ID確認や銀行カード番号入力など、幅広い一般向け機能を提供します。
2.png

内蔵して、アプリでサービスを利用できるようにする、銀行カード認識プラグインがあります。プラグインは、ユーザーに代わってカメラストリームを処理します。

開発を始める

1.準備

1.1 Huawei Mavenリポジトリをプロジェクトレベルのbuild.gradleファイルに追加する

Android Studioプロジェクトのルートディレクトリにあるbuild.gradleファイルを開き、Mavenリポジトリアドレスを追加します

buildscript {
    repositories {        
        maven {url 'http://developer.huawei.com/repo/'}
    }    }allprojects {
    repositories {       
        maven { url 'http://developer.huawei.com/repo/'}
    }}

1.2 SDK依存関係をアプリレベルのbuild.gradleファイルに追加する

dependencies{  
  implementation 'com.huawei.hms:ml-computer-vision-bcr:1.0.3.303' 
  implementation 'com.huawei.hms:ml-computer-card-bcr-plugin:1.0.3.300'  
  implementation 'com.huawei.hms:ml-computer-card-bcr-model:1.0.3.300' 

1.3 アプリのモデルが自動的に最新版に更新されるようにする

アプリがHUAWEI AppGalleryからダウンロードされるとすぐに、アプリの機械学習モデルが自動的に最新版に更新されるようにするには、以下の内容をAndroidManifest.xmlファイルに追加します。

   <manifest 
   ... 
   <meta-data              
       android:name="com.huawei.hms.ml.DEPENDENCY"   
       android:value= "bcr"/> 
       <!--If multiple models are required,set the parameter as follows:        
       android:value="object,ocr,face,label,icr,bcr,imgseg"-->  
   ... </manifest>

1.4 AndroidManifest.xmlファイルでカメラとストレージの権限を適用する

<uses-permission android:name="android.permission.CAMERA" /> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

2 コードの開発

2.1 認識結果の取得後に呼び出されるコールバック関数を作成する

onSuccessonCanceledonFailure、およびonDenied関数をオーバーライドします。

  • onSuccess:認識が成功すると呼び出されます。MLBcrCaptureResultは認識結果を示します。

  • onCanceled:ユーザーが認識をキャンセルすると呼び出されます

  • onFailure:認識が失敗すると呼び出されます。

  • onDenied:何らかの理由で認識要求が却下される(カメラが使用できないなど)と呼び出されます。

 private MLBcrCapture.Callback callback = new MLBcrCapture.Callback() { 
    @Override 
    public void onSuccess(MLBcrCaptureResult bankCardResult){ 
    }  
    @Override 
    public void onCanceled(){  
    }   
    @Override 
    public void onFailure(int retCode, Bitmap bitmap){  
    } 
    @Override 
    public void onDenied(){  
    }   };

2.2 認識機能のcaptureFrame APIを呼び出すための認識パラメータを設定する

認識結果は、2.1で作成したコールバック関数を通して返されます。

private void startCaptureActivity(MLBcrCapture.Callback callback) { 
    MLBcrCaptureConfig config = new MLBcrCaptureConfig.Factory() 
        .setOrientation(MLBcrCaptureConfig.ORIENTATION_AUTO) 
        .create(); 
    MLBcrCapture bankCapture = MLBcrCaptureFactory.getInstance().getBcrCapture(config); 
    bankCapture.captureFrame(this, callback); }

2.3 Recognitionボタンのコールバックで、2.2で定義したメソッドを呼び出す

@Override 
public void onClick(View v) { 
    switch (v.getId()) {  
        case R.id.detect: 
            startCaptureActivity(callback); 
            break; 
        default: 
            break; 
    } }

試してみましょう

銀行カード認識機能がどのようなものか見てみましょう。
3.gif

ソースコード

ソースコードをGitHub にアップロードしているので、機能の向上など自由にお試しください。
銀行カード認識のデモコードはMLKit-Sample\module-text\src\main\java\com\mlkit\sample\activity\BankCardRecognitionActivity.javaをご覧ください。
詳しくは、当社の公式ウェブサイトをご覧ください。

近日公開予定

これからも、実用的な場面でのHUAWEI ML Kitの使用方法をお知らせしますので、ワクワクするような内容に是非ご注目ください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

あのファーウェイスマホのカメラ機能をアプリにも取り入れる?

はじめに

ファーウェイのスマートフォンといえば、高性能なカメラ機能で有名ですよね。
アパーチャモード、夜景モード、ポートレートなどの処理にもハードウェアやSoc性能に依存します。
アプリ単体だと簡単に作れない機能です。

HMS CameraKit

現在販売しているファーウェイのスマートフォンにはHMS(Huawei Mobile Service)が搭載していて、アプリ開発向けの独自のSDK群が提供しています。
もちろん一般的なPushやIn App purchaseなどのSDKは提供している以外に、HUAWEI独自のSDKもアプリ開発者に提供しています。
それを取り入れたアプリをファーウェイ独自のアプリストアAppGallery公開すれば、全世界のファーウェイスマートフォンユーザーに配信することができます。

その中に、ファーウェイスマートフォンで使われているカメラ機能をSDKとして提供されたのがCameraKitです。
アパーチャ.png 夜景.png ポートレート.png
(引用元:https://developer.huawei.com/consumer/en/doc/development/Media-Guides/3180101

CameraKitをアプリに取り入れる準備

1、HUAWEI IDを新規登録
2、開発者アカウントを登録

GooglePlayやAppStoreと同様に開発者登録が必要ですが、
ファーウェイの開発者アカウント開設およびSDK運用はすべて無料で提供しています。
登録方法は公式サイトを参考:
https://developer.huawei.com/consumer/en/doc/10104

CameraKitの開発

CameraKitをAppGallery Connectコンソール画面から入手し、AndroidStudioプロジェクトに取り入れ、依存関係を追加します。

開発.png
(公式サイト:https://developer.huawei.com/consumer/en/doc/development/Media-Guides/3180103

次に、各カメラ機能のAPI導入:
フロントカメラHDRモード

Set mCurrentModeType to Mode.Type.HDR_MODE.

スーパーナイトモード

Set mCurrentModeType to Mode.Type.SUPER_NIGHT_MODE.

ウルトラワイドアングルモード

Set mCurrentModeType to Mode.Type.BOKEH_MODE.

レコーディングモード

Set mCurrentModeType to Mode.Type.VIDEO_MODE.

ポートレートモード

Set mCurrentModeType to Mode.Type.PORTRAIT_MODE.

ノーマルモード

Set mCurrentModeType to Mode.Type.NORMAL_MODE.

スーパースローモーションレコーディングモード

Set mCurrentModeType to Mode.Type.SUPER_SLOW_MOTION.

スローモーションレコーディングモード

Set mCurrentModeType to Mode.Type.SLOW_MOTION_MODE.

など

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

あのファーウェイスマホのカメラ機能をアプリでも取り入れる?

はじめに

ファーウェイのスマートフォンといえば、高性能なカメラ機能で有名ですよね。
アパーチャモード、夜景モード、ポートレートなどの処理にもハードウェアやSoc性能に依存します。
アプリ単体だと簡単に作れない機能です。

HMS CameraKit

現在販売しているファーウェイのスマートフォンにはHMS(Huawei Mobile Service)が搭載していて、アプリ開発向けの独自のSDK群が提供しています。
もちろん一般的なPushやIn App purchaseなどのSDKは提供している以外に、HUAWEI独自のSDKもアプリ開発者に提供しています。
それを取り入れたアプリをファーウェイ独自のアプリストアAppGallery公開すれば、全世界のファーウェイスマートフォンユーザーに配信することができます。

その中に、ファーウェイスマートフォンで使われているカメラ機能をSDKとして提供されたのがCameraKitです。
アパーチャ.png 夜景.png ポートレート.png
(引用元:https://developer.huawei.com/consumer/en/doc/development/Media-Guides/3180101

CameraKitをアプリに取り入れる準備

1、HUAWEI IDを新規登録
2、開発者アカウントを登録

GooglePlayやAppStoreと同様に開発者登録が必要ですが、
ファーウェイの開発者アカウント開設およびSDK運用はすべて無料で提供しています。
登録方法は公式サイトを参考:
https://developer.huawei.com/consumer/en/doc/10104

CameraKitの開発

CameraKitをAppGallery Connectコンソール画面から入手し、AndroidStudioプロジェクトに取り入れ、依存関係を追加します。

開発.png
(公式サイト:https://developer.huawei.com/consumer/en/doc/development/Media-Guides/3180103

次に、各カメラ機能のAPI導入:
フロントカメラHDRモード

Set mCurrentModeType to Mode.Type.HDR_MODE.

スーパーナイトモード

Set mCurrentModeType to Mode.Type.SUPER_NIGHT_MODE.

ウルトラワイドアングルモード

Set mCurrentModeType to Mode.Type.BOKEH_MODE.

レコーディングモード

Set mCurrentModeType to Mode.Type.VIDEO_MODE.

ポートレートモード

Set mCurrentModeType to Mode.Type.PORTRAIT_MODE.

ノーマルモード

Set mCurrentModeType to Mode.Type.NORMAL_MODE.

スーパースローモーションレコーディングモード

Set mCurrentModeType to Mode.Type.SUPER_SLOW_MOTION.

スローモーションレコーディングモード

Set mCurrentModeType to Mode.Type.SLOW_MOTION_MODE.

など

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

既存のAndroidアプリは意外と簡単にHMS対応に改修できます

はじめに

この前の記事では、HMS(Huawei Mobile Service)とは何なのかについて説明しました。今回は、どうやって既存のAndroidアプリを改修すればHMS端末(GMSが使用できないHuawei端末)で使えるようになるのかについて紹介したいと思います。タイトル通り、実は既存のAndroidアプリは意外と簡単にHMS対応に改修することができます。

SDKの使用状況によるアプリの分類

前回の記事で紹介したように、HMS端末ではGMSとfirebaseのSDKが使用できません。
しかし、HMS端末のOSはAOSP(Android Open Source Project)ベースですので、Androidのネティーブコンポーネントは継続的に使用できます。
AOSPとGMSの関係についてはこちらの記事でかなり分かりやすく紹介されていますので気になる方は確認してください。
https://qiita.com/hirossyi73/items/700e1be8e2b8f472b098

また、GMS以外のサードパーティーSDKの場合、GMSに依存していなければ継続的にHMS端末で使用できます。

まとめるとこんな感じになります。
1. GMSとfirebaseのSDK:使用できません
2. Androidのネティーブコンポーネント:継続的に使用可能
3. 3rd partyのSDK:GMSに依存していなければ使用可能

以上のSDKの使用状況に応じて、既存のAndroidアプリを以下の2種類に分けることができます。
1. GMSとfirebaseのSDKを使用していないアプリ:改修不要→そのままHMS端末で使用できます
2. それ以外のアプリ:若干の改修が必要

次に、2の改修が必要なアプリについて詳細を説明します。

どんな改修が必要なのか

必要な改修は、GMSとfirebase関連のSDKをHMSのSDKに差し替えるか、あるいは既存のアプリにHMSのSDKを追加するかだけです。

イメージ的にはこんな感じになります。
ghsolution.png

AOSPの部分は、HMS端末で継続的に使用できますので改修が不要で、HMSのSDKさえあればアプリはHMS端末で問題なく動きますのでHMS SDKが必須となります。

以上のように、HMS版アプリを開発するときにはおもに以下の2つのソリューションがあります。

1. GMS SDKをHMS SDKに差し替える(G2H)
2. 既存アプリにHMS SDKを追加する(G+H)

個人的には2のG+Hソリューションが非常に魅力的に感じていますので、G+Hソリューションについて紹介したいと思います。

G+Hソリューションの特徴と実現方法

G+Hソリューションの特徴としては:
Pros: 1つのパッケージで複数のプラットフォームに登録できます
Cons: パッケージのサイズが若干増えます

が挙げられます。

実現方法の例として、GoogleとHuaweiが提供しているAPIで端末のGMS/HMSの状況を判別し、それぞれの場合に該当するAPIを使用すればGMS端末とHMS端末両方で問題かく動作できるようになります。

GMSが使えるかどうかの判定方法:

GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == com.google.android.gms.common.ConnectionResult.SUCCESS

HMSた使えるかどうかの判定方法:

HuaweiApiAvailability.getInstance().isHuaweiMobileNoticeAvailable(this) == com.huawei.hms.api.ConnectionResult.SUCCESS

以上の判定方法を使用したG+Hソリューションのイメージ(GMSを優先的に使用する場合):

if(GMS avaliable){
    //元コード
}else if(HMS available){
    //HMSの場合のコード
}

この方法を採用することで、既存のAndroidアプリを若干修正することでGMS、HMS端末両方で問題なく使用できるアプリに改修できます。

終わりに

この記事では、既存のAndroidアプリのHMS対応方法の概要を説明しました。詳細な改修方法について、今後簡単なデモアプリを用いて説明していきたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Flutter/ Dart】外部アプリを起動して画像をシェアする方法

概要

共有機能(UI」で言うとのやつ)を実装するために試行錯誤した結果、採用した方法を記します。

結論

esys_flutter_shareを使って簡単に実装できました。

ちなみに他に試したのは下記です。
- Platform Channelsを使ってネイティブのコードに処理を委譲(外部アプリを起動)する。
- shareプラグイン(画像のシェアができず断念)

設定

pubspec.yaml
dependencies:
  esys_flutter_share: [version]

flutter pub getを忘れずに

コード

impportして

import 'package:esys_flutter_share/esys_flutter_share.dart';

この2行だけで終わり!

final ByteData bytes = await rootBundle.load('assets/image.png');
      await Share.file('タイトル', 'ファイル名', bytes.buffer.asUint8List(), 'image/png', text: '本文');

複数ファイルのシェアやHTTP経由で取得した画像のシェアも簡単にできるようです。

参考

pub.dev

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Android9.0 Pie Java】LINE風にチャット一覧画面→個人チャット画面の遷移アニメーションを実装(サンプルアプリ付)

環境

Android9.0 Pie Java

はじめに

以前投稿した、
【Android9.0 Pie Java】チャットアプリで横スワイプ→ダイアログ表示→削除を実装する
の続きになります。

  • チャット一覧の要素を押すと右から左へ覆い被さるようにチャット画面のfragmentが重なる
  • < ボタンを押すと左から右へチャット画面のfragmentが消える

以下のGifのように動作します。
3731939bc2a2b548bce0dd3ba2b8d615.gif

完成品URL

全てのコードを載せると大変なことになるので、この記事では省略しています。
チャット画面のlayoutやAdapter等のファイルも含めてDLして動かしてみたい方はこちらからどうぞ!
https://github.com/yuta-matsumoto/chat

コード

ChatListFragment.java

「チャット一覧の要素を押すと右から左へ覆い被さるようにチャット画面のfragmentが重なる」実装のコア部分になります。
チャット一覧の各要素のonItemClickの部分をピックアップします。
ChatListFragment.javaの全文はこちら

ChatListFragment.java
        // チャット一覧のアダプター
        final ChatListAdapter adapter = new ChatListAdapter(list) {
            @Override
            public void onItemClick(View view, int pos, List<ChatListRowData> list) {
                // 選択したユーザーの情報を渡す
                ChatFragment fragment = new ChatFragment();
                // fragment間のデータ受け渡しにはBundleが便利
                Bundle args = new Bundle();
                if (args != null) {
                    args.putString("userName", list.get(pos).getName());
                    fragment.setArguments(args);
                }
                // 画面遷移の準備
                FragmentTransaction transaction = getFragmentManager().beginTransaction();
                // 左から右へfragmentを重ねるアニメーション
                transaction.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right); // (1)
                // ChatListFragmentの上にChatFragmentを重ねる
                transaction.add(R.id.mainContainer, fragment, "fragment"); // (2)
                // バックスタックに加える
                transaction.addToBackStack(null);
                transaction.commit();
            }
        };

(1) Fragment間の画面遷移に好きなアニメーションを利用するために、
FragmentTransaction.setCustomAnimationsを利用しています。
res配下に以下の構成でアニメーションの定義を用意して読み込みます。

├res/
  ├anim/
    ├slide_in_left.xml
    └slide_out_right.xml

slide_in_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="100%p" android:toXDelta="0"
        android:duration="@android:integer/config_mediumAnimTime"/>
    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
        android:duration="@android:integer/config_mediumAnimTime" />
</set>
slide_out_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0" android:toXDelta="100%p"
        android:duration="@android:integer/config_mediumAnimTime"/>
    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
        android:duration="@android:integer/config_mediumAnimTime" />
</set>

(2) transaction.addを利用することで、ChatListFragmentの上にChatFragmentを重ねることができます。

ChatFragment.java

「< ボタンを押すと左から右へチャット画面のfragmentが消える」実装のコア部分になります。
チャット一覧の各要素のonViewCreatedの部分をピックアップします。
ChatFragment.javaの全文はこちら

ChatFragment.java
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        //・・・省略

        // <ボタンのリスナー
        ImageButton backButton = view.findViewById(R.id.backButton);
        backButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 画面遷移の準備
                FragmentTransaction transaction = getFragmentManager().beginTransaction();
                // 右から左へfragmentが消えるアニメーション
                transaction.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right); // (1)
                // ChatFragmentを削除
                transaction.remove(chatFragment); // (2)
                transaction.commit();
            }
        });
    }

(1) ChatListFragmentの記述と同様でOKです。

(2) transaction.removeを利用することで、ChatFragmentを削除しています。

以上です。

最後に

このアニメーションの動きの再現をするには、どうしても複数のActivityを利用すると上手く決まらず、
Activity自体重いので、1 Activity + N Fragmentの構成にしました。
最近実機にビルドしてもらったのですが、結構カッコよく動いたので嬉しいです!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む