Jump to content

Dave Nottage

Members
  • Content Count

    1609
  • Joined

  • Last visited

  • Days Won

    37

Posts posted by Dave Nottage


  1. 10 hours ago, vfbb said:

    the handling of incoming url of a universal link is different

    Yes, the application delegate needs to implement this method:

     

    https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623072-application?language=objc

     

    This means class_addmethod will need to be called to add it to the delegate (DelphiAppDelegate). It will also need an import for NSUserActivity, one of which follows (no guarantees as to being 100% accurate):

      NSUserActivityPersistentIdentifier = NSString;
    
      TNSUserActivityBlockMethod1 = procedure(inputStream: NSInputStream; outputStream: NSOutputStream; error: NSError) of object;
      TNSUserActivityBlockMethod2 = procedure of object;
    
      NSUserActivityClass = interface(NSObjectClass)
        ['{412EAEBF-5927-4D01-B83F-69D3B5DFE7B5}']
        {class} procedure deleteAllSavedUserActivitiesWithCompletionHandler(handler: TNSUserActivityBlockMethod2); cdecl;
        [MethodName('deleteSavedUserActivitiesWithPersistentIdentifiers:completionHandler:')]
        {class} procedure deleteSavedUserActivitiesWithPersistentIdentifiers(persistentIdentifiers: NSArray; handler: TNSUserActivityBlockMethod2); cdecl;
      end;
    
      NSUserActivity = interface(NSObject)
        ['{B8C2F6C9-31FE-4282-B7CA-98C96E163033}']
        function activityType: NSString; cdecl;
        procedure addUserInfoEntriesFromDictionary(otherDictionary: NSDictionary); cdecl;
        procedure becomeCurrent; cdecl;
        function delegate: Pointer; cdecl;
        function expirationDate: NSDate; cdecl;
        procedure getContinuationStreamsWithCompletionHandler(completionHandler: TNSUserActivityBlockMethod1); cdecl;
        function initWithActivityType(activityType: NSString): Pointer; cdecl;
        procedure invalidate; cdecl;
        function isEligibleForHandoff: Boolean; cdecl;
        function isEligibleForPrediction: Boolean; cdecl;
        function isEligibleForPublicIndexing: Boolean; cdecl;
        function isEligibleForSearch: Boolean; cdecl;
        function keywords: NSSet; cdecl;
        function needsSave: Boolean; cdecl;
        function persistentIdentifier: NSUserActivityPersistentIdentifier; cdecl;
        function referrerURL: NSURL; cdecl;
        function requiredUserInfoKeys: NSSet; cdecl;
        procedure resignCurrent; cdecl;
        procedure setDelegate(delegate: Pointer); cdecl;
        procedure setEligibleForHandoff(eligibleForHandoff: Boolean); cdecl;
        procedure setEligibleForPrediction(eligibleForPrediction: Boolean); cdecl;
        procedure setEligibleForPublicIndexing(eligibleForPublicIndexing: Boolean); cdecl;
        procedure setEligibleForSearch(eligibleForSearch: Boolean); cdecl;
        procedure setExpirationDate(expirationDate: NSDate); cdecl;
        procedure setKeywords(keywords: NSSet); cdecl;
        procedure setNeedsSave(needsSave: Boolean); cdecl;
        procedure setPersistentIdentifier(persistentIdentifier: NSUserActivityPersistentIdentifier); cdecl;
        procedure setReferrerURL(referrerURL: NSURL); cdecl;
        procedure setRequiredUserInfoKeys(requiredUserInfoKeys: NSSet); cdecl;
        procedure setSupportsContinuationStreams(supportsContinuationStreams: Boolean); cdecl;
        procedure setTargetContentIdentifier(targetContentIdentifier: NSString); cdecl;
        procedure setTitle(title: NSString); cdecl;
        procedure setUserInfo(userInfo: NSDictionary); cdecl;
        procedure setWebpageURL(webpageURL: NSURL); cdecl;
        function supportsContinuationStreams: Boolean; cdecl;
        function targetContentIdentifier: NSString; cdecl;
        function title: NSString; cdecl;
        function userInfo: NSDictionary; cdecl;
        function webpageURL: NSURL; cdecl;
      end;
      TNSUserActivity = class(TOCGenericImport<NSUserActivityClass, NSUserActivity>) end;

    The method implementation should probably be (again no guarantees):

    class function TApplicationDelegate.applicationContinueUserActivityRestorationHandler(self: id; _cmd: SEL; application: PUIApplication;
      userActivity: Pointer; restorationHandler: Pointer): Boolean;

    As far as I know, it doesn't necessarily have to be patched in FMX.Platform.iOS since you should be able to call class_addmethod anywhere, as long as you pass it the correct class function.

     

    Hopefully this will give you head start.

    • Like 2
    • Thanks 1

  2. 6 hours ago, Hans♫ said:

    Now it links with the FBSDK 4.36 without problems, and after a few hours of work to adapt my code to the new API version, everything works!

    Excellent! There's someone in another post here asking about whether there are updated imports for the FB SDK. Perhaps you can help them, or at least give them an idea as to whether everything still works anyway. (using 4.36)


  3. 1 hour ago, Turan Can said:

    android.os.SystemProperties

    If there's a class called that, it's undocumented.

     

    If you're after a unique id for the device, you're probably better off using something like this:

    uses
      Androidapi.JNI.Provider, Androidapi.Helpers;
    
    // **** NOTE: Use this value with care, as it is reset if the device is rooted, or wiped
    function GetUniqueDeviceID: string;
    var
      LName: JString;
    begin
      LName := TJSettings_Secure.JavaClass.ANDROID_ID;
      Result := JStringToString(TJSettings_Secure.JavaClass.getString(TAndroidHelper.ContentResolver, LName));
    end;

     


  4. 2 hours ago, Vandrovnik said:

    (But I would not see Idxxx.dcu even in projects where I do use Indy, because there I am using the Indy which came with Delphi, so it is not recompiled with the project.)

    You would if you included the Indy source path. If the callstack says it's being used, you're using it.

     

    Does your app use any tethering functionality? That ultimately includes Indy units.

    • Thanks 1

  5. 1 hour ago, Kryvich said:

    Have you obtain an Android phone with HDD? )

    I'm assuming he means any file-based media that it can access.

    9 hours ago, Turan Can said:

    Is there an example for Android?

    This may be of use to you:

    uses
      Androidapi.JNI.JavaTypes, Androidapi.JNIBridge, Androidapi.JNI.Os, Androidapi.JNI.GraphicsContentViewText, Androidapi.Helpers;
    
    type
      JStorageManager = interface;
      JStorageVolume = interface;
    
      JStorageManagerClass = interface(JObjectClass)
        ['{0F83E5E0-9AE5-41F8-9FA1-E91CABBC6720}']
        function _GetACTION_MANAGE_STORAGE: JString; cdecl;
        function _GetEXTRA_REQUESTED_BYTES: JString; cdecl;
        function _GetEXTRA_UUID: JString; cdecl;
        function _GetUUID_DEFAULT: JUUID; cdecl;
        property ACTION_MANAGE_STORAGE: JString read _GetACTION_MANAGE_STORAGE;
        property EXTRA_REQUESTED_BYTES: JString read _GetEXTRA_REQUESTED_BYTES;
        property EXTRA_UUID: JString read _GetEXTRA_UUID;
        property UUID_DEFAULT: JUUID read _GetUUID_DEFAULT;
      end;
    
      [JavaSignature('android/os/storage/StorageManager')]
      JStorageManager = interface(JObject)
        ['{A7190FB5-1DBE-4A4E-8A21-A6215C00243C}']
        function getAllocatableBytes(storageUuid: JUUID): Int64; cdecl;
        function getCacheQuotaBytes(storageUuid: JUUID): Int64; cdecl;
        function getCacheSizeBytes(storageUuid: JUUID): Int64; cdecl;
        function getMountedObbPath(rawPath: JString): JString; cdecl;
        function getPrimaryStorageVolume: JStorageVolume; cdecl;
        function getStorageVolume(&file: JFile): JStorageVolume; cdecl;
        function getStorageVolumes: JList; cdecl;
        function getUuidForPath(path: JFile): JUUID; cdecl;
        function isAllocationSupported(fd: JFileDescriptor): boolean; cdecl;
        function isCacheBehaviorGroup(path: JFile): boolean; cdecl;
        function isCacheBehaviorTombstone(path: JFile): boolean; cdecl;
        function isEncrypted(&file: JFile): boolean; cdecl;
        function isObbMounted(rawPath: JString): boolean; cdecl;
        function mountObb(rawPath: JString; key: JString; listener: JOnObbStateChangeListener): boolean; cdecl;
        // function openProxyFileDescriptor(mode : Integer; callback : JProxyFileDescriptorCallback; handler : JHandler) : JParcelFileDescriptor; cdecl;
        function unmountObb(rawPath: JString; force: boolean; listener: JOnObbStateChangeListener): boolean; cdecl;
        procedure allocateBytes(fd: JFileDescriptor; bytes: Int64); cdecl; overload;
        procedure allocateBytes(storageUuid: JUUID; bytes: Int64); cdecl; overload;
        procedure setCacheBehaviorGroup(path: JFile; group: boolean); cdecl;
        procedure setCacheBehaviorTombstone(path: JFile; tombstone: boolean); cdecl;
      end;
    
      TJStorageManager = class(TJavaGenericImport<JStorageManagerClass, JStorageManager>)
      end;
    
      JStorageVolumeClass = interface(JObjectClass)
        ['{C11D1D2A-77D0-4D1A-B4B9-5042B60BADB0}']
        function _GetCREATOR: JParcelable_Creator; cdecl;
        function _GetEXTRA_STORAGE_VOLUME: JString; cdecl;
        property CREATOR: JParcelable_Creator read _GetCREATOR;
        property EXTRA_STORAGE_VOLUME: JString read _GetEXTRA_STORAGE_VOLUME;
      end;
    
      [JavaSignature('android/os/storage/StorageVolume')]
      JStorageVolume = interface(JObject)
        ['{F6555252-D4E1-405B-BAAB-2C8F59A01F41}']
        function createAccessIntent(directoryName: JString): JIntent; cdecl;
        function describeContents: Integer; cdecl;
        function equals(obj: JObject): boolean; cdecl;
        function getDescription(context: JContext): JString; cdecl;
        function getState: JString; cdecl;
        function getUuid: JString; cdecl;
        function hashCode: Integer; cdecl;
        function isEmulated: boolean; cdecl;
        function isPrimary: boolean; cdecl;
        function isRemovable: boolean; cdecl;
        function toString: JString; cdecl;
        procedure writeToParcel(parcel: JParcel; flags: Integer); cdecl;
      end;
      TJStorageVolume = class(TJavaGenericImport<JStorageVolumeClass, JStorageVolume>)
      end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      LService: JObject;
      LStorageManager: JStorageManager;
      LVolumes: JList;
      LVolume: JStorageVolume;
      I: Integer;
    begin
      LService := TAndroidHelper.Activity.getSystemService(TJContext.JavaClass.STORAGE_SERVICE);
      LStorageManager := TJStorageManager.Wrap(TAndroidHelper.JObjectToID(LService));
      LVolumes := LStorageManager.getStorageVolumes;
      for I := 0 to LVolumes.size - 1 do
      begin
        LVolume := TJStorageVolume.Wrap(LVolumes.get(I));
        Memo1.Lines.Add(Format('%s (%s)', [JStringToString(LVolume.getDescription(TAndroidHelper.Context)), JStringToString(LVolume.getUuid)]));
      end;
    end;

     

    • Like 1
    • Thanks 1

  6. 15 hours ago, microtronx said:

    will that tLocation use a lot of energy/battery or will it only be active each x minutes as defined in this line:

    That's just the timer. Battery life will be affected by the settings used with the actual location services, as determined by MonitoringDistance and MonitoringInterval. There's some information here about the best strategies to use:

     

    https://developer.android.com/guide/topics/location/strategies

     

     

    • Thanks 1
×