Delphi XE6で作成したBluetoothを使用するAndroidアプリケーションをDelphi XE7に移行したときの話

やったこと

先日、Delphi XE6で作成したBluetoothを使用するAndroidアプリケーションをDelphi XE7から導入されたBluetooth APIを使用するように修正しました。
そのときに感じたことを書きます。
(BluetoothはBluetooth LEではなく、クラシックBluetoothです。)

修正前のアプリケーション

  • 開発環境…Delphi XE6
  • Bluetooth…AndroidのBluetooth API

修正後のアプリケーション

  • 開発環境…Delphi XE7
  • Bluetooth…DelphiのBluetooth API

DelphiのBluetooth APIはAndroidのBluetooth APIに似ている

DelphiのBluetooth APIはAndroidのBluetooth APIに似ていると感じました。
AndroidのBluetooth APIを参考にして、DelphiのBluetooth APIを設計したのかもしれません。

知っているAPIによく似ていたので、DelphiのBluetooth APIの使い方はすぐにわかりました。
学習コストは低いと思いました。

DelphiのBluetooth APIに書き換えてソースコードが見やすくなった

AndroidのAPIを使用するときは、Delphiのデータ型とJavaのデータ型を変換する処理が必要になります。

Delphiのデータ型からJavaのデータ型に変換してAndroid APIに引数として渡します。
Android APIの返値はJavaのデータ型ですから、Delphiのデータ型に戻します。
このような変換作業が何度もソースコード上に現れます。

DelphiのBluetooth APIに書き換えることによって、Javaのデータ型とDelphiのデータ型を変換する必要がなくなりました。
ソースコードはずっと見やすくなりました。

足りない機能はAndroid APIを呼び出す

DelphiのBluetooth APIはAndroidのBluetooth APIのすべての機能をサポートしているわけではありません。
実装されていない機能もありました。
たとえば、デバイスがBluetoothを使用できるかを調べたり、Bluetoothが有効になっているかを取得する機能はDelpphiのBluetooth APIにはありませんでした。

DelphiのBluetooth APIに実装されていない機能は、AndroidのBluetooth APIを呼び出すことで対応しました。
ネイティブのAPIを簡単に呼び出せるので、DelphiのAPIがサポートしていなくても大きな問題にはなりませんでした。

Windowsでも動く

DelphiのBluetooth APIに変更する作業が終わった後、試しにターゲットデバイスをWindowsにして実行してみたところ、アプリケーションがそのまま動作しました。
これには驚きました。

開発中はAndroidデバイスにアプリケーションを転送して動作を確認していましたが、転送には時間がかかります。
はじめからWindows上で動作を確認していれば、もっと早く開発できたと思います。

まとめ

特に大きな問題もなく、AndroidのBluetooth APIからDelphiのBluetooth APIに移行することができました。

WindowsでもBluetoothが使えることにもっと早く気がついていれば、開発がもっとスムーズにできたと思います。

第2回 RAD Studio勉強会@Osaka

とあるデータベースアプリケーションのバージョンアップの歴史(注意:実際には存在しません。)

Windowsアプリケーション

Win

Windowsアプリケーションでは、撮影した写真や位置情報を登録するのが大変でした。

モバイルアプリケーション

Mobile

モバイルアプリケーションにすると、スマートフォンについているカメラやGPSを使って、写真や位置情報の登録が簡単になりました。
ですが、文字入力が大変でした。

Windowsアプリケーションとモバイルアプリケーションのハイブリット

ApplicationTethering

スマートフォンのカメラやGPSで写真や位置情報をとり、Wi-FiやBluetoothでパソコンに送って、登録します。
文字入力はパソコンで行います。

パソコンの得意なことはパソコンで、スマートフォンが得意なことはスマートフォンで。

アプリケーションテザリングのすすめ

Delphi/C++Builderならアプリケーションテザリングでデバイスの連携がとても簡単です。

勉強会では、スマートフォンのカメラで撮った写真やGPSの位置情報を、Windowsアプリケションに送る方法を説明します。

C++Builder XE6でAndroidスマートフォンの電話番号などの端末情報を取得するには

C++Builder XE6でAndroidスマートフォンの電話番号などの端末情報を取得するサンプルアプリケーションです。

FireMonkeyモバイルアプリケーションを作成します。

フォームにボタンコンポーネント(TButton)とメモコンポーネント(TMemo)を配置します。

JTelephonyManager01

ボタンコンポーネントのクリックイベントを記述します。

#include <Androidapi.Helpers.hpp>
#include <Androidapi.JNI.JavaTypes.hpp>
#include <Androidapi.JNI.GraphicsContentViewText.hpp>
#include <Androidapi.JNIBridge.hpp>
#include <Androidapi.JNI.Telephony.hpp>
#include <FMX.Helpers.Android.hpp>

void __fastcall TForm1::Button1Click(TObject *Sender) {
    _di_JObject TelephonyServiceNative = SharedActivityContext()->getSystemService(TJContext::JavaClass->TELEPHONY_SERVICE);
    _di_JTelephonyManager TelephonyManager = TJTelephonyManager::Wrap(((_di_ILocalObject)TelephonyServiceNative)>GetObjectID());

    Memo1->Lines->BeginUpdate();
    try {
        Memo1->Lines->Add(L"電話番号");
        Memo1->Lines->Add(JStringToString(TelephonyManager->getLine1Number()));
        Memo1->Lines->Add(L"デバイスID");
        Memo1->Lines->Add(JStringToString(TelephonyManager->getDeviceId()));
        Memo1->Lines->Add(L"SIMの国コード");
        Memo1->Lines->Add(JStringToString(TelephonyManager->getSimCountryIso()));
        Memo1->Lines->Add(L"MCC+MNC (mobile country code + mobile network code)");
        Memo1->Lines->Add(JStringToString(TelephonyManager->getSimOperator()));
        Memo1->Lines->Add(L"サービスプロバイダの名前");
        Memo1->Lines->Add(JStringToString(TelephonyManager->getSimOperatorName()));
        Memo1->Lines->Add(L"SIMのシリアル番号");
        Memo1->Lines->Add(JStringToString(TelephonyManager->getSimSerialNumber()));
        Memo1->Lines->Add(L"ボイスメールナンバー");
        Memo1->Lines->Add(JStringToString(TelephonyManager->getVoiceMailNumber()));
        Memo1->Lines->Add(L"SIMの状態");
        const int SimState = TelephonyManager->getSimState();
        if (SimState == TJTelephonyManager::JavaClass->SIM_STATE_UNKNOWN)
            Memo1->Lines->Add(L"SIM_STATE_UNKNOWN");
        if (SimState == TJTelephonyManager::JavaClass->SIM_STATE_ABSENT)
            Memo1->Lines->Add(L"SIM_STATE_ABSENT");
        if (SimState == TJTelephonyManager::JavaClass->SIM_STATE_PIN_REQUIRED)
            Memo1->Lines->Add(L"SIM_STATE_PIN_REQUIRED");
        if (SimState == TJTelephonyManager::JavaClass->SIM_STATE_NETWORK_LOCKED)
            Memo1->Lines->Add(L"SIM_STATE_NETWORK_LOCKED");
        if (SimState == TJTelephonyManager::JavaClass->SIM_STATE_READY)
            Memo1->Lines->Add(L"SIM_STATE_READY");
    }
    __finally {
        Memo1->Lines->EndUpdate();
    }
}

アプリケーションを実行し、ボタンをクリックします。

メモコンポーネントに端末情報が表示されます。

Delphi XE6でAndroidスマートフォンの電話番号などの端末情報を取得するには

Delphi XE6でAndroidスマートフォンの電話番号などの端末情報を取得するサンプルアプリケーションです。

FireMonkeyモバイルアプリケーションを作成します。

フォームにボタンコンポーネント(TButton)とメモコンポーネント(TMemo)を配置します。

JTelephonyManager01

ボタンコンポーネントのクリックイベントを記述します。

uses
  Androidapi.Helpers,
  Androidapi.JNI.JavaTypes,
  Androidapi.JNI.GraphicsContentViewText,
  Androidapi.JNIBridge,
  Androidapi.JNI.Telephony,
  FMX.Helpers.Android;


procedure TForm1.Button1Click(Sender: TObject);
var
  TelephonyServiceNative: JObject;
  TelephonyManager: JTelephonyManager;
  SimState: Integer;
begin
  TelephonyServiceNative := SharedActivityContext.getSystemService
    (TJContext.JavaClass.TELEPHONY_SERVICE);
  TelephonyManager := TJTelephonyManager.Wrap
    ((TelephonyServiceNative as ILocalObject).GetObjectID);

  Memo1.Lines.BeginUpdate;
  try
    Memo1.Lines.Add('電話番号');
    Memo1.Lines.Add(JStringToString(TelephonyManager.getLine1Number));
    Memo1.Lines.Add('デバイスID');
    Memo1.Lines.Add(JStringToString(TelephonyManager.getDeviceId));
    Memo1.Lines.Add('SIMの国コード');
    Memo1.Lines.Add(JStringToString(TelephonyManager.getSimCountryIso));
    Memo1.Lines.Add('MCC+MNC (mobile country code + mobile network code)');
    Memo1.Lines.Add(JStringToString(TelephonyManager.getSimOperator));
    Memo1.Lines.Add('サービスプロバイダの名前');
    Memo1.Lines.Add(JStringToString(TelephonyManager.getSimOperatorName));
    Memo1.Lines.Add('SIMのシリアル番号');
    Memo1.Lines.Add(JStringToString(TelephonyManager.getSimSerialNumber));
    Memo1.Lines.Add('ボイスメールナンバー');
    Memo1.Lines.Add(JStringToString(TelephonyManager.getVoiceMailNumber));
    Memo1.Lines.Add('SIMの状態');
    SimState := TelephonyManager.getSimState;
    if SimState = TJTelephonyManager.JavaClass.SIM_STATE_UNKNOWN then
      Memo1.Lines.Add('SIM_STATE_UNKNOWN');
    if SimState = TJTelephonyManager.JavaClass.SIM_STATE_ABSENT then
      Memo1.Lines.Add('SIM_STATE_ABSENT');
    if SimState = TJTelephonyManager.JavaClass.SIM_STATE_PIN_REQUIRED then
      Memo1.Lines.Add('SIM_STATE_PIN_REQUIRED');
    if SimState = TJTelephonyManager.JavaClass.SIM_STATE_NETWORK_LOCKED then
      Memo1.Lines.Add('SIM_STATE_NETWORK_LOCKED');
    if SimState = TJTelephonyManager.JavaClass.SIM_STATE_READY then
      Memo1.Lines.Add('SIM_STATE_READY');
  finally
    Memo1.Lines.EndUpdate;
  end;
end;

アプリケーションを実行し、ボタンをクリックします。

メモコンポーネントに端末情報が表示されます。