iphonelazext: changing run simulator to apples instruments utility. Updated the frames to use resources files, instead of the old include files

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4401 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
skalogryz
2015-12-07 04:04:01 +00:00
parent b9b381633f
commit df4dfb0ba4
8 changed files with 507 additions and 50 deletions

View File

@ -1,27 +1,30 @@
inherited iPhoneSpecificOptions: TiPhoneSpecificOptions
object iPhoneSpecificOptions: TiPhoneSpecificOptions
Left = 0
Height = 473
Top = 0
Width = 487
ClientHeight = 473
ClientWidth = 487
DesignLeft = 567
DesignTop = 313
object lblRTLUtils: TLabel[0]
TabOrder = 0
DesignLeft = 373
DesignTop = 176
object lblRTLUtils: TLabel
Left = 16
Height = 18
Height = 16
Top = 184
Width = 92
Width = 91
Caption = 'RTL units path'
ParentColor = False
end
object lblCompilerPath: TLabel[1]
object lblCompilerPath: TLabel
Left = 16
Height = 18
Height = 16
Top = 152
Width = 55
Width = 57
Caption = 'Compiler'
ParentColor = False
end
object edtCompilerPath: TEdit[2]
object edtCompilerPath: TEdit
Left = 136
Height = 22
Top = 152
@ -30,16 +33,16 @@ inherited iPhoneSpecificOptions: TiPhoneSpecificOptions
TabOrder = 0
Text = 'edtCompilerPath'
end
object lblXCodeProject: TLabel[3]
object lblXCodeProject: TLabel
Left = 16
Height = 18
Height = 16
Top = 128
Width = 394
Width = 389
Caption = 'Specific ARM compiler settings (for generated Xcode projects)'
ParentColor = False
ParentFont = False
end
object edtRTLPath: TEdit[4]
object edtRTLPath: TEdit
Left = 136
Height = 22
Top = 184
@ -48,7 +51,7 @@ inherited iPhoneSpecificOptions: TiPhoneSpecificOptions
TabOrder = 1
Text = 'edtRTLPath'
end
object edtCompilerOptions: TEdit[5]
object edtCompilerOptions: TEdit
Left = 136
Height = 22
Top = 216
@ -58,26 +61,26 @@ inherited iPhoneSpecificOptions: TiPhoneSpecificOptions
TabOrder = 2
Text = 'edtCompilerOptions'
end
object lblCmpOptions: TLabel[6]
object lblCmpOptions: TLabel
Left = 16
Height = 18
Height = 16
Top = 216
Width = 106
Width = 109
Caption = 'Compiler options'
ParentColor = False
ParentFont = False
OnClick = lblCmpOptionsClick
end
object Label5: TLabel[7]
object Label5: TLabel
Left = 16
Height = 18
Height = 16
Top = 16
Width = 97
Width = 96
Caption = 'Platforms path:'
ParentColor = False
ParentFont = False
end
object edtPlatformsPath: TEdit[8]
object edtPlatformsPath: TEdit
Left = 125
Height = 22
Top = 16
@ -86,67 +89,67 @@ inherited iPhoneSpecificOptions: TiPhoneSpecificOptions
TabOrder = 3
Text = 'edtPlatformsPath'
end
object lblSimSettings: TLabel[9]
object lblSimSettings: TLabel
Left = 16
Height = 18
Height = 16
Top = 256
Width = 161
Caption = 'iPhone Simulator settings'
ParentColor = False
end
object edtSimBundle: TEdit[10]
object edtSimBundle: TEdit
Left = 160
Height = 22
Top = 286
Top = 360
Width = 306
Anchors = [akTop, akLeft, akRight]
TabOrder = 4
Text = 'edtSimBundle'
end
object edtSimApps: TEdit[11]
object edtSimApps: TEdit
Left = 160
Height = 22
Top = 318
Top = 392
Width = 306
Anchors = [akTop, akLeft, akRight]
TabOrder = 5
Text = 'edtSimApps'
end
object lblSimBundle: TLabel[12]
object lblSimBundle: TLabel
Left = 16
Height = 18
Top = 287
Width = 111
Height = 16
Top = 361
Width = 113
Caption = 'iPhoneSim bundle'
ParentColor = False
end
object lblSimAppPath: TLabel[13]
object lblSimAppPath: TLabel
Left = 16
Height = 18
Top = 318
Width = 141
Height = 16
Top = 392
Width = 142
Caption = 'Sim Applications path:'
ParentColor = False
end
object Button1: TButton[14]
object Button1: TButton
Left = 16
Height = 20
Top = 56
Width = 112
Width = 115
AutoSize = True
Caption = 'Scan for SDKs'
OnClick = Button1Click
TabOrder = 6
end
object Label1: TLabel[15]
object Label1: TLabel
Left = 16
Height = 18
Height = 16
Top = 88
Width = 129
Caption = 'Default SDK version:'
ParentColor = False
end
object cmbDefaultSDK: TComboBox[16]
object cmbDefaultSDK: TComboBox
Left = 152
Height = 20
Top = 88
@ -155,4 +158,46 @@ inherited iPhoneSpecificOptions: TiPhoneSpecificOptions
Style = csDropDownList
TabOrder = 7
end
object ddPhoneSimType: TComboBox
Left = 160
Height = 20
Top = 288
Width = 304
Anchors = [akTop, akLeft, akRight]
ItemHeight = 0
ItemIndex = 0
Items.Strings = (
'Simulator via instruments'
)
Style = csDropDownList
TabOrder = 8
Text = 'Simulator via instruments'
end
object lblSimType: TLabel
Left = 16
Height = 16
Top = 288
Width = 95
Caption = 'Simulator Type'
ParentColor = False
OnClick = lblSimTypeClick
end
object lblDefaultDevice: TLabel
Left = 16
Height = 16
Top = 323
Width = 118
Caption = 'Default Sim Device'
ParentColor = False
end
object ddSimDevice: TComboBox
Left = 160
Height = 20
Top = 323
Width = 306
Anchors = [akTop, akLeft, akRight]
ItemHeight = 0
Style = csDropDownList
TabOrder = 9
end
end

View File

@ -21,7 +21,7 @@ interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, StdCtrls,
IDEOptionsIntf, ProjectIntf,
iPhoneExtOptions;
iPhoneExtOptions, iphonesimctrl;
type
@ -30,6 +30,8 @@ type
TiPhoneSpecificOptions = class(TAbstractIDEOptionsEditor)
Button1: TButton;
cmbDefaultSDK: TComboBox;
ddSimDevice: TComboBox;
ddPhoneSimType: TComboBox;
edtCompilerPath: TEdit;
edtRTLPath: TEdit;
edtCompilerOptions: TEdit;
@ -37,6 +39,8 @@ type
edtSimBundle: TEdit;
edtSimApps: TEdit;
Label1: TLabel;
lblDefaultDevice: TLabel;
lblSimType: TLabel;
lblRTLUtils: TLabel;
lblSimAppPath: TLabel;
lblCompilerPath: TLabel;
@ -47,6 +51,7 @@ type
lblSimBundle: TLabel;
procedure Button1Click(Sender: TObject);
procedure edtCompilerOptionsChange(Sender: TObject);
procedure lblSimTypeClick(Sender: TObject);
procedure lblCmpOptionsClick(Sender: TObject);
private
{ private declarations }
@ -61,6 +66,8 @@ type
implementation
{$R *.lfm}
{ TiPhoneSpecificOptions }
procedure TiPhoneSpecificOptions.lblCmpOptionsClick(Sender: TObject);
@ -88,6 +95,11 @@ begin
end;
procedure TiPhoneSpecificOptions.lblSimTypeClick(Sender: TObject);
begin
end;
function TiPhoneSpecificOptions.GetTitle: String;
begin
Result:='Files';
@ -101,6 +113,10 @@ end;
procedure TiPhoneSpecificOptions.ReadSettings(AOptions: TAbstractIDEOptions);
var
opt : TiPhoneEnvironmentOptions;
idx : integer;
i : integer;
j : integer;
sd : TSimDevice;
begin
if not Assigned(AOptions) or not (AOptions is TiPhoneEnvironmentOptions) then Exit;
opt:=TiPhoneEnvironmentOptions(AOptions);
@ -116,6 +132,21 @@ begin
cmbDefaultSDK.Items.Clear;
opt.GetSDKVersions(cmbDefaultSDK.Items);
cmbDefaultSDK.ItemIndex:=cmbDefaultSDK.Items.IndexOf(opt.DefaultSDK);
if EnvOptions.DeviceCount=0 then
EnvOptions.DeviceListReload;
idx:=-1;
ddSimDevice.Clear;
for i:=0 to EnvOptions.DeviceCount-1 do begin
sd:=EnvOptions.Device[i];
if sd.isavail then begin
j:=ddSimDevice.Items.Add( sd.name );
ddSimDevice.Items.Objects[j]:=sd;
if sd.id=EnvOptions.DefaultDeviceID then
idx:=j;
end;
end;
if idx>=0 then ddSimDevice.ItemIndex:=idx;
end;
procedure TiPhoneSpecificOptions.WriteSettings(AOptions: TAbstractIDEOptions);
@ -132,6 +163,8 @@ begin
opt.SimBundle:=edtSimBundle.Text;
opt.SimAppsPath:=edtSimApps.Text;
if ddSimDevice.ItemIndex>=0 then
opt.DefaultDeviceID:=TSimDevice(ddSimDevice.Items.Objects[ddSimDevice.ItemIndex]).id;
opt.Save;
end;
@ -141,7 +174,6 @@ begin
end;
initialization
{$I environment_iphone_options.lrs}
RegisterIDEOptionsEditor(iPhoneEnvGroup, TiPhoneSpecificOptions, iPhoneEnvGroup+1);
end.

View File

@ -27,7 +27,7 @@ uses
project_iphone_options, xcodetemplate,
iPhoneExtOptions, iPhoneExtStr, iPhoneBundle, lazfilesutils;
iPhoneExtOptions, iPhoneExtStr, iPhoneBundle, lazfilesutils, iphonesimctrl;
procedure Register;
@ -456,14 +456,13 @@ begin
IDEMessagesWindow.AddMsg(strXcodeUpdated, '', 0);
end;
procedure TiPhoneExtension.SimRun(Sender: TObject);
procedure SimRunDirect;
var
t : TProcess;
path : String;
begin
t :=TProcess.Create(nil);
try
//ProjectBuilding(nil);
path:=IncludeTrailingPathDelimiter(EnvOptions.SimBundle)+'Contents/MacOS/iPhone Simulator';
EnvOptions.SubstituteMacros(path);
t.CommandLine:='"'+path+'"';
@ -476,6 +475,28 @@ begin
t.Free;
end;
function SimRunInstruct(var err: string): Boolean;
begin
if EnvOptions.DefaultDeviceID='' then begin
err:='Device type is not specified';
Result:=false;
Exit;
end;
Result:=true;
iphonesimctrl.RunSim( EnvOptions.DefaultDeviceID );
end;
procedure TiPhoneExtension.SimRun(Sender: TObject);
var
err : string;
begin
if not SimRunInstruct(err) then begin
ShowMessage('Unable to run Simulator. '+err);
Exit;
end;
end;
{procedure TiPhoneExtension.isProjectClicked(Sender: TObject);
begin
if not Assigned(Sender) or not Assigned(LazarusIDE.ActiveProject) then Exit;

View File

@ -21,7 +21,7 @@ interface
uses
Classes, SysUtils, IDEOptionsIntf, LazIDEIntf, ProjectIntf, MacroIntf,
iPhoneBundle, DOM, XMLRead, XMLConf, XcodeUtils, FileUtil;
iPhoneBundle, XMLConf, XcodeUtils, FileUtil, iphonesimctrl;
const
DefaultResourceDir = 'Resources';
@ -75,8 +75,13 @@ type
fSimAppsPath : String;
fSimBundle : String;
fDefaultSDK : String;
fDefaultSimType : String;
fDefaultDeviceID : String;
fVersions : TStringList;
fDeviceList : TList;
function GetDevice(i: integer): TSimDevice;
function GetDeviceCount: Integer;
protected
function XMLFileName: String;
@ -100,6 +105,9 @@ type
procedure GetSDKVersions(Strings: TStrings);
procedure RefreshVersions;
procedure DeviceListClear;
procedure DeviceListReload;
property PlatformsBaseDir: String read fPlatformsBaseDir write fPlatformsBaseDir;
property CompilerPath: String read fCompilerPath write fCompilerPath;
property BaseRTLPath: String read fBaseRTLPath write fBaseRTLPath;
@ -109,6 +117,12 @@ type
property SimAppsPath: String read fSimAppsPath write fSimAppsPath;
property DefaultSDK: String read fDefaultSDK write fDefaultSDK;
property DefaultSimType: String read fDefaultSimType write fDefaultSimType; // it's currently Simulator via instruments
property DefaultDeviceID: String read fDefaultDeviceID write fDefaultDeviceID;
property DeviceCount: Integer read GetDeviceCount;
property Device[i: integer]: TSimDevice read GetDevice;
end;
function EnvOptions: TiPhoneEnvironmentOptions;
@ -175,6 +189,17 @@ begin
Result:=EnvOptions;
end;
function TiPhoneEnvironmentOptions.GetDevice(i: integer): TSimDevice;
begin
if (i<0) and (i>=fDeviceList.Count) then Result:=nil
else Result:=TSimDevice(fDeviceList[i]);
end;
function TiPhoneEnvironmentOptions.GetDeviceCount: Integer;
begin
Result:=fDeviceList.Count;
end;
function TiPhoneEnvironmentOptions.XMLFileName: String;
begin
Result:=IncludeTrailingPathDelimiter(LazarusIDE.GetPrimaryConfigPath)+DefaultXMLName;
@ -240,12 +265,15 @@ begin
fSimBundle := GetDefaultSimBundlePath;
fCompilerPath := '/usr/local/bin/fpc';
fVersions:=TStringList.Create;
fDeviceList:=TList.Create;
end;
destructor TiPhoneEnvironmentOptions.Destroy;
begin
ClearVersionsInfo;
fVersions.Free;
DeviceListClear;
fDeviceList.Free;
inherited Destroy;
end;
@ -267,6 +295,7 @@ begin
fSimBundle := UTF8Encode(xmlcfg.GetValue('SimBundle', fSimBundle));
fSimAppsPath := UTF8Encode(xmlcfg.GetValue('SimAppPath', fSimAppsPath));
fDefaultSDK := UTF8Encode(xmlcfg.GetValue('DefaultSDK', fDefaultSDK));
fDefaultDeviceID := UTF8Encode(xmlcfg.GetValue('DefaultDevice', fDefaultDeviceID));
RefreshVersions;
if (fDefaultSDK = '') and (fVersions.Count>0) then
@ -296,6 +325,7 @@ begin
xmlcfg.SetValue('SimBundle', UTF8Decode(fSimBundle));
xmlcfg.SetValue('SimAppPath', UTF8Decode(fSimAppsPath));
xmlcfg.SetValue('DefaultSDK', UTF8Decode(fDefaultSDK));
xmlcfg.SetValue('DefaultDevice', UTF8Decode(fDefaultDeviceID));
finally
xmlcfg.Free;
end;
@ -350,6 +380,20 @@ begin
ScanForSDK(EnvOptions.PlatformsBaseDir, @FoundSDK);
end;
procedure TiPhoneEnvironmentOptions.DeviceListClear;
var
i : integer;
begin
for i:=0 to fDeviceList.Count-1 do
TObject(fDeviceList[i]).Free;
fDeviceList.Clear;
end;
procedure TiPhoneEnvironmentOptions.DeviceListReload;
begin
ListDevice(fDeviceList);
end;
{ TiPhoneProjectOptions }
procedure TiPhoneProjectOptions.Reset;

View File

@ -0,0 +1,151 @@
unit iphonesimctrl;
{$mode delphi}
interface
uses
Classes, SysUtils, process
, jsonparser, fpjson
{$ifdef unix}, BaseUnix{$endif} // for StopProc()
;
procedure RunSim(const SimName: string);
function RunAppOnSim(const AppID, DeviceID: string; WaitDebugger: Boolean; var pid: Integer; var outstr: string): Boolean;
procedure StopProc(pid: Integer);
type
TSimDevice = class(TObject)
public
sdk : string;
state : string;
isavail : Boolean;
name : string;
id : string;
end;
function ListDevice(lst: TList): Boolean;
implementation
procedure RunSim(const SimName: string);
var
outstr: string;
begin
outstr:='';
RunCommand('xcrun', ['instruments', '-w' ,SimName], outstr);
end;
function RunAppOnSim(const AppID, DeviceID: string; WaitDebugger: Boolean; var pid: Integer; var outstr: string): Boolean;
var
devid: string;
err : Integer;
i : Integer;
j : Integer;
begin
if DeviceID='' then devid:='booted'
else devid:=DeviceID;
if WaitDebugger then
Result:=RunCommand('xcrun', ['simctl', 'launch', '-w', devid, AppID], outstr)
else
Result:=RunCommand('xcrun', ['simctl', 'launch', devid, AppID], outstr);
if Result and (length(outstr)>0) then begin
i:=length(outstr);
// skipping white spaces, if any
while (i>0) and not (outstr[i] in ['0'..'9']) do dec(i);
j:=i;
while (i>0) and (outstr[i] in ['0'..'9']) do dec(i);
Val( copy(outstr, i+1, j-i), pid, err);
writeln('err = ', err);
if err>0 then pid:=0;
end;
end;
procedure StopProc(pid: Integer);
begin
{$ifdef unix}
FpKill(pid, SIGTERM);
{$endif}
end;
function JSStr(v: TJSONData): string;
begin
if not Assigned(v) then Result:=''
else Result:=v.AsString;
end;
function JsonToSimDev(oj: TJsonObject): TSimDevice;
begin
Result:=nil;
if not Assigned(oj) or (oj.JSONType<>jtObject) then Exit;
Result:=TSimDevice.Create;
Result.state:=JSStr(oj.Find('state'));
Result.isavail:=JSStr(oj.Find('availability'))='(available)';
Result.name:=JSStr(oj.Find('name'));
Result.id:=JSStr(oj.Find('udid'));
end;
procedure CollectDevices(list: TJSONArray; const asdk: string; dst: TList);
var
oj : TJSONObject;
i : Integer;
d : TSimDevice;
begin
for i:=0 to list.Count-1 do begin
oj:=TJSONObject(list.Items[i]);
d:=JsonToSimDev(oj);
d.sdk:=asdk;
if Assigned(d) then
dst.Add(d);
end;
end;
function ListDevice(lst: TList): Boolean;
var
s : string;
j : TJSONParser;
dt : TJSONData;
d : TJSONObject;
v : TJSONData;
i : Integer;
begin
s:='';
RunCommand('xcrun', ['simctl', 'list', 'devices', '-j'], s);
try
dt:=nil;
j:=TJSONParser.Create(s, []);
try
dt:=j.Parse;
finally
j.Free;
end;
try
Result:=false;
if not Assigned(dt) or (dt.JSONType<>jtObject) or (dt.Count=0) then Exit;
v:=TJSONObject(dt).Find('devices');
if not Assigned(v) or (v.JSONType<>jtObject) then Exit;
d:=TJSONObject(v);
for i:=0 to d.Count-1 do begin
if Pos('iOS', d.Names[i])=1 then begin
if (d.items[i].JSONType=jtArray) then
CollectDevices( TJSONArray(d.Items[i]), d.Names[i], lst);
end;
end;
finally
dt.Free;
end;
except
on e:exception do
writeln('error: ', e.message);
end;
end;
end.

View File

@ -91,6 +91,8 @@ type
implementation
{$R *.lfm}
{ TiPhoneProjectOptionsEditor }
procedure TiPhoneProjectOptionsEditor.cmbSDKsChange(Sender: TObject);
@ -568,8 +570,6 @@ const
iPhoneOptions = 10000; //todo: get it dynamically
initialization
{$I project_iphone_options.lrs}
writeln('registering iPhone proj editor');
//RegisterIDEOptionsEditor(iPhonePrjGroup, TiPhoneProjectOptionsEditor, iPhoneOptions);
RegisterIDEOptionsEditor(GroupProject, TiPhoneProjectOptionsEditor, iPhoneOptions);

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="9"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="testlaunch"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<i18n>
<EnableI18N LFM="False"/>
</i18n>
<VersionInfo>
<StringTable ProductVersion=""/>
</VersionInfo>
<BuildModes Count="1">
<Item1 Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
</local>
</RunParams>
<Units Count="1">
<Unit0>
<Filename Value="testlaunch.lpr"/>
<IsPartOfProject Value="True"/>
</Unit0>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<Target>
<Filename Value="testlaunch"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value=".."/>
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<SyntaxMode Value="Delphi"/>
</SyntaxOptions>
</Parsing>
<Linking>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,88 @@
program testlaunch;
{$mode delphi}{$H+}
uses
{$IFDEF UNIX}cthreads,{$ENDIF}
Classes, iphonesimctrl;
procedure PrintList;
var
lst : TList;
i : integer;
dev : TSimDevice;
begin
lst := TList.Create;
try
ListDevice(lst);
for i:=0 to lst.Count-1 do begin
dev := TSimDevice(lst[i]);
writeln(dev.id,' ',dev.isavail,' ',dev.sdk,' ', dev.name,' ',dev.state);
end;
finally
lst.Free;
end;
end;
procedure RunDevice(const nm: string);
begin
RunSim(nm);
end;
procedure RunApp(const appid: string);
var
res : string;
pid : Integer;
begin
res:='';
if not RunAppOnSim(appid, '', False, pid, res) then begin
writeln('failed to run app');
end else begin
writeln('launching!');
writeln('pid = ', pid);
writeln('outstr: ');
writeln(res);
end;
end;
procedure PrintHelp;
begin
writeln('testlaunch %action% [%parameters%]');
writeln('action:');
writeln(' list - list devices');
writeln(' run %deviceid% - runs a simulator with specified id');
writeln(' runapp %appid% - runs an application on booted device');
end;
var
act : string = '';
procedure ParseParam;
begin
if ParamCount=0 then Exit;
act:=ParamStr(1);
act:=lowercase(act);
end;
begin
if ParamCount=0 then begin
PrintHelp;
exit;
end;
ParseParam;
if act='list' then PrintList
else if act='run' then begin
if ParamCount=1 then begin
writeln('Please specify deviceid');
Exit;
end;
RunDevice(ParamStr(2));
end else if act='runapp' then begin
if ParamCount=1 then begin
writeln('Please specify application id to run');
Exit;
end;
RunApp(ParamStr(2));
end;
end.