Status: Tethering
- die Windows-App kann sowohl andere Manager und Profiles im Netzwerk suchen und finden (discover) als auch gefunden werden und dann zwischen beiden Apps Daten austauschen
- die Android-App kann sowohl andere Manager und Profiles im Netzwerk suchen und finden (discover) als auch gefunden werden und dann zwischen beiden Apps Daten austauschen
- Permission Internet muss auf "true" gesetzt sein
- die iOS-App kann andere Manager und Profiles im Netzwerk suchen und finden (discover), diesem auch Daten schicken und Antworten empfangen, kann aber unter iOS 14.x nicht gefunden werden (<iOS 14 funktioniert).
Ursache: DoOnReceiveData wird unter iOS 14.x nie errreicht (gleiches gilt für MacOS 11.x)
- Es muss via
https://developer.apple.com/contact/...king-multicast die Berechtigung erfragt werden, das Entitlement Multicast zu setzen,
damit iOS 14.x funktioniert; im Projekt ist das Entitlement aber nicht zu setzen, dies passiert über das Provision Profile automatisch (außer man erzeugt
die Entitlement-Datei manuell);
Delphi-Quellcode:
<key>
com.apple.developer.networking.multicast</key>
<true/>
- die MacOS-App kann andere Manager und Profiles im Netzwerk suchen und finden (discover), diesem auch Daten schicken und Antworten empfangen, kann aber unter MacOS 11.x nicht gefunden werden (<MacOS 11.x funktioniert).
Ursache: DoOnReceiveData wird unter MacOS 11.x nie errreicht (gleiches gilt für iOS 14.x)
Folgende Entitlements wurden gesetzt (Entitlement.TemplateOSX.xml oder via Projekt-Optionen):
Delphi-Quellcode:
<key>
com.apple.security.network.client</key>
<true/>
<key>
com.apple.security.network.server</key>
<true/>
Tipp 1: Formulardesigner: das Profile auf Enabled setzen und den Manager aus Disabled und dem Profile keinen Manager zuweisen.
Im Programm-Code den Manager auf Enabled setzen und direkt davor dem Profile den Manager zuweisen.
Sonst wird schon sehr viel initialisert (z.B. der Netzwerk-Adapter) bevor man erstmalig Zugriff im Code auf die Komponenten hat.
Delphi-Quellcode:
CommandApp.Manager := CommandManager;
CommandManager.Enabled := True;
Tipp 2: für iOS müssen eventuell alle
Exception gefangen werden, weil ansonsten das nicht erfolgreiche binden eines Sockets zum Abbruch führen kann
Socket-Fehler # 48Adresse wird bereits verwendet:
$0000000100BCFDD0 _ZN7Idstack8TIdStack16RaiseSocketErrorEi + 316
$0000000100BD0B74 _ZN7Idstack8TIdStack20RaiseLastSocketErrorEv + 72
$0000000100BD0A18 _ZN7Idstack8TIdStack19CheckForSocketErrorEi + 44
$0000000100BCBD00 _ZN15Idstackvclposix16TIdStackVCLPosix4BindEiN6Sys tem13UnicodeStringEtN8Idglobal12TIdIPVersionE + 344
$0000000100BD99E8 _ZN14Idsockethandle15TIdSocketHandle4BindEv + 316
$0000000100BF84F8 _ZN17Idcustomtcpserver18TIdCustomTCPServer14StartL isteningEv + 188
Delphi-Quellcode:
Application.OnException:=TgoExceptionReporter.ExceptionHandler;
TMessageManager.DefaultManager.SubscribeToMessage(TgoExceptionReportMessage, HandleExceptionReport);
Tipp 3:
IP-Adresse des eigenen Adapters nicht automatisch setzen lassen, sondern selbst per
Indy auswählen:
Delphi-Quellcode:
uses IdStack, IdGlobal;
function getIPv4Address():
String;
var
AAddresses: TIdStackLocalAddressList;
LAddr: TIdStackLocalAddress;
I: Integer;
prefNetwork,
IP:
String;
begin
AAddresses:=TIdStackLocalAddressList.Create();
prefNetwork:='
192.';
//can be set also outside this functionality before the manager is enabled or the manager-attribute of the profile is set
Result:='
';
try
GStack.GetLocalAddressList(AAddresses);
for I := 0
to AAddresses.Count-1
do
begin
LAddr:=AAddresses[I];
IP:=LAddr.IPAddress;
if ((
IP<>'
127.0.0.1')
and ((Result='
')
or ((prefNetwork>'
')
and (pos(prefNetwork,
IP)=1)
and (pos(prefNetwork,Result)<>1))))
then
begin
case LAddr.IPVersion
of
Id_IPv4:
begin
mlog.info('
Found IP-address*: '+
IP);
Result:=
IP;
end;
Id_IPv6:
begin
mlog.info('
Found IP-address: '+
IP);
end;
end;
end else
mlog.info('
Found IP-address: '+
IP);
end;
finally
AAddresses.Free;
end;
end;
Dies passiert an zwei Stellen:
System.Tether.Manager.pas
Delphi-Quellcode:
constructor TTetheringAdapter.Create;
var ip:
String;
begin
inherited;
FRemoteManagers := TTetheringManagerInfoList.Create;
ip:=getIPv4Address();
if (
ip>'
')
then
FAdapterConnectionString :=
ip
else
FAdapterConnectionString := TTetheringManagerCommunicationThread.EMPTYTOKEN;
end;
System.Tether.NetworkAdapter.pas
Delphi-Quellcode:
procedure TTetheringNetworkManagerCommunicationThread.Execute;
...
if not LListening
then
raise ETetheringException.Create(SManagerNetworkCreation);
var ip:
String;
ip:=TStringUtils.getIPv4Address();
if (
ip>'
')
then
LRemoteConnectionString :=
ip + TetheringConnectionSeparator + FTarget
else
LRemoteConnectionString := EMPTYTOKEN + TetheringConnectionSeparator + FTarget;
Zur Sicherheit habe ich es noch hier eingebaut, da wird es aber höchstwahrscheinlich nicht gebraucht:
System.Tether.NetworkAdapter.pas
Delphi-Quellcode:
procedure TTetheringNetworkAdapterCommon.DoDiscoverManagers(Timeout: Cardinal;
const ATargetList: TTetheringTargetHosts;
const AProfileGroups, AProfileTexts: TArray<
string>);
...
LCommand := TTetheringManagerCommand.Create(TTetheringNetworkManagerCommunicationThread.TetheringDiscoverManagers,
FAdapterConnectionString, Manager.Version, [FCommunicationThread.FTarget, LGroups, LTexts]);
end else begin
if (pos(TTetheringNetworkManagerCommunicationThread.EMPTYTOKEN,FAdapterConnectionString)>0)
then
begin
var ip:
String;
ip:=TStringUtils.getIPv4Address();
if (
ip>'
')
then
FAdapterConnectionString:=StringReplace(FAdapterConnectionString,TTetheringNetworkManagerCommunicationThread.EMPTYTOKEN,
ip,[]);
end;