Einzelnen Beitrag anzeigen

philipp.hofmann

Registriert seit: 21. Mär 2012
Ort: Hannover
891 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: Status: Tethering - noch Probleme mit MacOS und iOS

  Alt 7. Jun 2021, 16:47
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;

Geändert von philipp.hofmann ( 7. Jun 2021 um 16:50 Uhr)
  Mit Zitat antworten Zitat