Delphi/C++Builder 10.1 Berlin Update2のMac用PAServerをダウンロードするには

docwikiの「Mac でのプラットフォーム アシスタントのインストール」にはリンクがありませんが、
Delphi/C++Builder 10.1 Berlin Update2のMac用PAServerは、
次のURLからダウンロードできました。

Delphi 10.1 Berlin Update2でiOS 10用にユーザーデータのアクセス目的を記述するには

iOS 10から、カメラなどを使用するときには、info.plistに特定のキーと使用目的を記述するようになりました。

Delphi 10.1 Berlin Update2では、プロジェクトオプションのバージョン情報画面で、設定できます。

delphi101belrin_infoplist

位置情報へのアクセス (常に)

  • キー
    NSLocationAlwaysUsageDescription


  • アプリが常にユーザーの位置情報にアクセスする理由

位置情報へのアクセス (使用中のみ)

  • キー
    NSLocationWhenInUseUsageDescription


  • アプリがフォアグラウンドで実行されているときなど、アプリがユーザーの位置情報にアクセスする理由

連絡先へのアクセス

  • キー
    NSContactsUsageDescription


  • アプリがユーザーの連絡先にアクセスする理由

フォトライブラリへのアクセス

  • キー
    NSPhotoLibraryUsageDescription


  • アプリがユーザーの写真ライブラリにアクセスする理由

カメラへのアクセス

  • キー
    NSCameraUsageDescription


  • アプリがデバイスのカメラにアクセスする理由

Delphiのフォーマッタ(コードの整形)でDataMoudleが壊れる

TDataMoudleにはClassGroupプロパティがあります。
このプロパティで、データモジュールがVCL用かFMX用かフレームワークに依存しないかを設定します。

たとえばTTimerコンポーネントはVCL用のVcl.ExtCtrls.TTimerとFMX用のFMX.Types.TTimerがあります。
使用するコンポーネントとClassGroupで設定したフレームワークを一致させる必要があります。

formatter01

オブジェクトインスペクタでClassGroupプロパティを設定すると、ユニットファイルには次のような指令が追加されます。

ClassGroupがFMX.Controls.TControlの場合:

{%CLASSGROUP 'FMX.Controls.TControl'}

フォーマッタのコメントスペースの設定の「{ および (* コメントスペースの設定」は初期値が「内側と外側」になっています。
この設定でコードを整形すると、ClassGroupプロパティによって追加された指令が次のようになります。

{ %CLASSGROUP 'FMX.Controls.TControl' }

「{」「}」の間に空白が追加されました。

このように空白が追加されると、ClassGroupプロパティの値は未設定の状態になります。

ClassGroupプロパティの値が設定されていない状態になると、コンポーネントとフレームワークに不一致が生じます。
その結果、IDEでデータモジュールを読み込むときにエラーが発生します。

エラーが発生した場合は、ClassGroupプロパティの指令を修正すれば、元の状態に戻ります。

Androidアプリでネイティブコントロールをフォームに配置するには

Androidアプリでネイティブコントロールをフォームに配置するには

Delphi 10.1 BerlinのFireMonkeyアプリケーションでAndroidのネイティブコントロールをフォームに配置する方法です。

コントロールを配置する

DelphiのフォームにAndroidのネイティブコントロールを配置するには、JNativeLayoutを使用します。

uses Androidapi.JNI.Embarcadero;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { private 宣言 }
    FNativeLayout: JNativeLayout;
  public
    { public 宣言 }
  end;

Androidのネイティブコントロールを使用するときは、
CallInUIThread関数またはCallInUIThreadAndWaitFinishing関数を使用して、
AndroidのUIスレッドで行います。

CallInUIThread関数は非同期で処理を行います。
CallInUIThreadAndWaitFinishing関数は処理が完了するまでブロックします。

uses FMX.Helpers.Android;

CallInUIThreadAndWaitFinishing(
  procedure
  begin
    // ネイティブコントロールを使用する
  end);

JNativeLayoutのインスタンスを作成します。

uses Androidapi.Helpers, FMX.Platform.Android;

FNativeLayout := TJNativeLayout.JavaClass.Init(
  TAndroidHelper.Activity,
  MainActivity.getWindow.getDecorView.getWindowToken);

ネイティブコントロールを作成し、JNativeLayoutに登録します。
今回のサンプルではEditTextを配置します。

uses Androidapi.JNI.Widget;

EditText := TJEditText.JavaClass.Init(TAndroidHelper.Activity);
FNativeLayout.setControl(EditText);

JNativeLayoutに登録できるコントロールは一つだけです。
また、nilを登録すると、登録されていたコントロールが削除されます。

コントロールの位置と大きさを設定します。
この設定は、JNativeLayoutにコントロールを登録した後に行います。

  FNativeLayout.setPosition(50, 300);
  FNativeLayout.setSize(400, 200);

コントロールを非表示にする

事前にウィンドウのサイズを取得しておきます。

type
  TForm1 = class(TForm)
  …
  private
    { private 宣言 }
    FRealBounds: TRect;
    procedure CalcRealBorder;
  …
  end;

procedure TForm1.CalcRealBorder;
var
  NativeWin: JWindow;
  ContentRect: JRect;
begin
  NativeWin := TAndroidHelper.Activity.getWindow;
  if NativeWin <> nil then
  begin
    ContentRect := TJRect.Create;
    NativeWin.getDecorView.getDrawingRect(ContentRect);
    FRealBounds := Rect(ContentRect.left, ContentRect.top, ContentRect.Right,
      ContentRect.bottom);
  end
  else
    FRealBounds := TRect.Empty;
end;

コントロールを非表示にする処理は、UIスレッドで行います。

procedure TForm1.ButtonHideClick(Sender: TObject);
begin
  CallInUIThread(
    procedure
    begin
      if FEditText.getVisibility <> TJView.JavaClass.INVISIBLE then
      begin
        FEditText.setVisibility(TJView.JavaClass.INVISIBLE);
        FNativeLayout.setPosition(
          FRealBounds.Right * 2,
          FRealBounds.Height * 2);
      end;
    end);
end;

コントロールを表示する

非表示にしたコントロールを再表示します。

procedure TForm1.ButtonShowClick(Sender: TObject);
begin
  CallInUIThread(
    procedure
    begin
      FNativeLayout.setPosition(50, 300);
      FNativeLayout.setSize(400, 200);

      if FEditText.getVisibility <> TJView.JavaClass.VISIBLE then
      begin
        FEditText.setVisibility(TJView.JavaClass.VISIBLE);
      end;
    end);
end;

サンプルアプリケーション

Createボタンを押すとコントロールを作成し、Hideボタンで非表示にし、Showボタンで再表示します。

device-2016-10-15-193530

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes,
  System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics,
  FMX.Dialogs, Androidapi.JNI.Embarcadero, FMX.Controls.Presentation,
  FMX.StdCtrls, Androidapi.JNI.Widget;

type
  TForm1 = class(TForm)
    ButtonCreate: TButton;
    ButtonShow: TButton;
    ButtonHide: TButton;
    procedure ButtonCreateClick(Sender: TObject);
    procedure ButtonShowClick(Sender: TObject);
    procedure ButtonHideClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { private 宣言 }
    FEditText: JEditText;
    FNativeLayout: JNativeLayout;
    FRealBounds: TRect;
    procedure CalcRealBorder;
  public
    { public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

uses Androidapi.Helpers, FMX.Platform.Android, FMX.Helpers.Android,
  Androidapi.JNI.GraphicsContentViewText;

procedure TForm1.ButtonCreateClick(Sender: TObject);
begin
  CallInUIThreadAndWaitFinishing(
    procedure
    begin
      FNativeLayout := TJNativeLayout.JavaClass.Init(TAndroidHelper.Activity,
        MainActivity.getWindow.getDecorView.getWindowToken);

      FEditText := TJEditText.JavaClass.Init(TAndroidHelper.Activity);
      FEditText.setText(StrToJCharSequence('テスト'),
        TJTextView_BufferType.JavaClass.NORMAL);

      FNativeLayout.setControl(FEditText);
      FNativeLayout.setPosition(50, 300);
      FNativeLayout.setSize(400, 200);
    end);
end;

procedure TForm1.ButtonHideClick(Sender: TObject);
begin
  CallInUIThread(
    procedure
    begin
      if FEditText.getVisibility <> TJView.JavaClass.INVISIBLE then
      begin
        FEditText.setVisibility(TJView.JavaClass.INVISIBLE);
        FNativeLayout.setPosition(FRealBounds.Right * 2,
          FRealBounds.Height * 2);
      end;
    end);
end;

procedure TForm1.ButtonShowClick(Sender: TObject);
begin
  CallInUIThread(
    procedure
    begin
      FNativeLayout.setPosition(50, 300);
      FNativeLayout.setSize(400, 200);

      if FEditText.getVisibility <> TJView.JavaClass.VISIBLE then
      begin
        FEditText.setVisibility(TJView.JavaClass.VISIBLE);
      end;
    end);
end;

procedure TForm1.CalcRealBorder;
var
  NativeWin: JWindow;
  ContentRect: JRect;
begin
  NativeWin := TAndroidHelper.Activity.getWindow;
  if NativeWin <> nil then
  begin
    ContentRect := TJRect.Create;
    NativeWin.getDecorView.getDrawingRect(ContentRect);
    FRealBounds := Rect(ContentRect.left, ContentRect.top, ContentRect.Right,
      ContentRect.bottom);
  end
  else
    FRealBounds := TRect.Empty;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  CalcRealBorder;
end;

end.

ソースコードはGitHubで取得できます。