B4A Library CloudRail - CloudStorage (Dropbox, GoogleDrive, OneDrive and Box) Payment (PayPal, Stripe), POI

This is a Wrapper for the CloudStorage API from CloudRail.

At this point of development there is no Social-module wrapped. CloudRail does support more than just the CloudStorage-Api. But it was this i was interested in so i wrote the wrap for them...

I leave it up to the community to extend the library; i´ll share the written JAVA-Code

Requirements:
- B4A 6+ as the library is using a aar
- Account at CloudRail. Note that they also provide free subscription.
https://cloudrail.com/cloudrail-pricing/
- The file cloudrail-si.aar which can be downloaded here.
- An ClientID and Secret from the content-provider you want to use.
Dropbox
GoogleDrive
OneDrive
Box

Installation: Copy all three files from the library zip to your additional libs folder.
CloudRail.xml, CloudRail.jar and cloudrail-si.aar



Example-Code (for Dropbox)

B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim dropbox As Dropbox
    Dim cr As CloudRail
End Sub

B4X:
Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
    cr.Initialize("CloudRail","cloudrailid")
End Sub
Sub CloudRail_Ready(Success As Boolean)
    Log($"CloudRail_Ready(${Success})"$)
    If Success Then
        'dropbox.Initialize("Dropbox","client id","client secret")
    End If
End Sub

B4X:
Sub Dropbox_Ready(Success As Boolean)
    Log($"Dropbox_Ready(${Success})"$)
    dropbox.getChildren("/")
    dropbox.getChildren("/B4A")
    dropbox.checkAllocation
    dropbox.download("/B4A/MaterialDesign-Webfont-master.zip",rp.GetSafeDirDefaultExternal("Downloads"),"MaterialWebfont.zip")
End Sub
Sub Dropbox_DownloadFinished(success As Boolean, info As String, filePath As String, destPath As String, destFile As String)
    Log($"Dropbox_DownloadFinished(${destFile}->${success},${destFile},${filePath})"$)
End Sub
Sub Dropbox_Allocation(alloc As Object)
    Log($"Dropbox_Allocation()"$)
    If alloc <> Null Then
        Dim sa As SpaceAllocation = alloc
        Log($"${sa.Used} Used"$)
        Log($"${sa.Total} Total"$)
    End If
End Sub
Sub Dropbox_MetaData(path As String, meta As Object)
    Log($"Dropbox_MetaData(${path},${meta})"$)
End Sub
Sub Dropbox_Login(Success As Boolean)
    Log($"Dropbox_Login(${Success})"$)
End Sub
Sub Dropbox_Children(folder As List, files As List)
    Log($"Dropbox_Children()"$)
    If folder <> Null Then
        Log($"folder: ${folder.Size}"$)
    End If
    If files <> Null Then
        Log($"files: ${files.Size}"$)
    End If
    'Log($"Dropbox_Children(${folder})"$)
End Sub

CloudRail
Author:
DonManfred (wrapper)
Version: 1.5
CloudRail
Events:

  • Ready (Success As Boolean)
Methods:
  • validateKey As void
  • Initialize (ba As anywheresoftware.b4a.BA, EventName As java.lang.String, AppKey As java.lang.String) As void
Permissions:
  • android.permission.ACCESS_NETWORK_STATE
  • android.permission.INTERNET
  • android.permission.READ_EXTERNAL_STORAGE
  • android.permission.WRITE_EXTERNAL_STORAGE
Properties:
  • AppKey As java.lang.String

Business CloudStorage:
AmazonS3
Backblaze
GoogleCloudPlatform
MicrosoftAzure
Rackspace
OneDriveBusiness


Cloud Storage:
Box
Google-Drive
Dropbox
Egnyte
OneDrive









SpaceAllocation
Methods:

  • hashCode As int
  • equals (o As java.lang.Object) As boolean
  • toString As java.lang.String
  • IsInitialized As boolean
  • Initialize (ba As anywheresoftware.b4a.BA, EventName As java.lang.String, space As com.cloudrail.si.types.SpaceAllocation) As void
Properties:
  • Used As java.lang.Long
  • Total As java.lang.Long
 

Attachments

  • CloudRailV1.51.zip
    189.7 KB · Views: 498
  • CloudRailV1.52.zip
    188.7 KB · Views: 509
  • CloudRailV1.54.zip
    188.8 KB · Views: 707
  • cloudrail-si.zip
    453.7 KB · Views: 684
  • cloudrailEx.zip
    8 KB · Views: 668
Last edited:

DonManfred

Expert
Licensed User
Longtime User
Ok, nun habe ich verstanden. Ich werde - für die Allgemeinheit - weiter in English antworten.

Ahh, ok. Now i understand. I tried to investigate it yesterday.
With the same result as you and Mahares.

Always i had to reauthenticate.

I did not find a solution for it till now.

But i´ll make a ticket on the Cloudrail-Support to ask what to do.
 

Mahares

Expert
Licensed User
Longtime User
Problem gelöst,

driveToken = drive.saveAsString
If driveToken.Length>0 Then drive.loadAsString(driveToken)
1. Could you share with the rest of us in English how you prevent the annoying screen from appearing.
2. Where did you exactly put the 2 lines of code above in your project.
3. Googledrive has a client ID(appkey) and a secret. What do you mean by 'drivetoken'
 

Paulsche

Well-Known Member
Licensed User
Longtime User
1. Create a global String Variable "dim driveToken ="" as string" .

B4X:
Sub Drive_Ready(Success As Boolean)
    Log($"Drive_Ready(${Success})"$)
    If Success Then
        BTN18BackupGoogleDrive.Enabled        = True                                            'Backup-Button deaktivieren
        BTN18BackupGoogleDrive.TextColor    = Colors.RGB(0,0,189)       
        If driveToken.Length>0 Then drive.loadAsString(driveToken)
    Else
        BTN18BackupGoogleDrive.Enabled         = False
        BTN18RestoreGoogleDrive.Enabled        = False
        LBL18RestoreGoogleDriveInfo.Text    = ""       
    End If
End Sub

B4X:
Sub Drive_UploadFinished(destPath As String, info As String, success As Boolean)
    driveToken             = drive.saveAsString                                    'Zugriff Token in Variable speichern
End Sub

"DriveToken = drive.saveAsString" stores all relevant data for access in the variable driveToken.
 

Paulsche

Well-Known Member
Licensed User
Longtime User
How can i check if an upload / download is possible, if e.g. No internet is available?
The events "CloudRail_Ready" and "Drive_Ready" always report "success", even if I disable Internet on the phone, and the upload wants to start and run on error, APP is terminated.
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User
"DriveToken = drive.saveAsString" stores all relevant data for access in the variable driveToken.
Please note that this only works after you finally finish a upload/download/dir-listing... Once the result event is raised you can store the credentials with
drive.saveAsString
 

Mahares

Expert
Licensed User
Longtime User
you can store the credentials with
drive.saveAsString
Shouldn't this string be saved in a text file or somewhere so it can be retrieved the next time you do an upload or download. I do not think the answer we got in post#44 is complete. Something is missing. I tried the suggestion in post#44, but you are shown every time the annoying google drive screen
 

DonManfred

Expert
Licensed User
Longtime User
Shouldn't this string be saved in a text file or somewhere so it can be retrieved the next time you do an upload or download.
Yes, sure. You can do it the same way like i did in my Dropbox-Example (the java Dropbox-wrap)


B4X:
Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
    cr.Initialize("CloudRail","xxx")

End Sub
Sub CloudRail_Ready(Success As Boolean)
    Log($"CloudRail_Ready(${Success})"$)
    If Success Then
        Dim dummy As String
        dummy = Starter.kvs.GetDefault("token", "")
        If dummy <> "" And dummy <> $"[{}]"$ Then
            Log($"ReuseToken(${dummy})"$)
            token = dummy
            drive.loadAsString(dummy)
        Else
            Log($"Drive.Initialize()"$)
            drive.Initialize("Drive","bbbb","cccc")
        End If
    End If
End Sub

Like i wrote. ou can save the token after you firstly finished a job. download, upload, dir-listing...
In my app i´m calling getchildren for a folder. inside the event i save the token

B4X:
Sub Drive_Children(folder As List, files As List)
    Log($"Drive_Children()"$)
    Dim t As String = drive.saveAsString
    Log("Token="&t)
    token = t
    Starter.kvs.Put("token", token)
 

iz0ndg

Active Member
Licensed User
Longtime User
Hi,
first of all thanks to Manfred for this useful library, all work ok but if i create subfolder on Google Drive i have this error:
B4X:
  drive.createFolder("/Turnariovf")

B4X:
** Service (starter) Create **
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
CloudRail_Ready(true)
Drive_Ready(true)
java.lang.Exception: Sub drive_createFolder was not found.
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
   at anywheresoftware.b4a.BA$2.run(BA.java:328)
   at android.os.Handler.handleCallback(Handler.java:751)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:154)
   at android.app.ActivityThread.main(ActivityThread.java:6176)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778)

but in code i have this sub:

B4X:
Sub Drive_CreateFolder(folderPath As String)
   Log($"Drive folder created"$)
End Sub

The folder is created in Google Drive.

Any Idea?
 

Mahares

Expert
Licensed User
Longtime User
I have been spending hours on this CloudRail GoogleDrive library with no luck:
The first time I run it, it prompts me for authentication and runs well:
B4X:
googledrive_Ready(true)
show me token:
** Activity (main) Pause, UserClosed = false **
sending message to waiting queue (CallSubDelayed - JobDone)
running waiting messages (1)
** Activity (main) Resume **
my upload : true
Token in KVS is [{"refreshToken":"1\/3HrMJWZexVCZykF00RXzmuYJ9mHYj28qZZcbI","accessToken":"29.Ci_BA9yHmJw9MBREfOL23jQrDdN_JozxxKdTLoX4PBvThQO7QCfaxW3QkVxW9exWZg","expireIn":1482869498646}]

After the first time, it crashes with this error:

B4X:
Sub CloudRail_Ready(Success As Boolean)
    Log($"CloudRail_Ready(${Success})"$)
    If Success Then
        Dim dummy As String
        dummy = Starter.kvs.GetDefault("token", "")
        If dummy <> "" And dummy <> $"[{}]"$ Then
            Log($"ReuseToken(${dummy})"$)
            Token = dummy
            googledrive.loadAsString(dummy)   'ERROR HERE


B4X:
CloudRail_Ready(true)
ReuseToken([{"refreshToken":"1\/3HrMJWZexVCZykF00RXzmuYJ9mHYj28qZZcbI","accessToken":"29.Ci_BA9yHmJw9MBREfOL23jQrDdN_JozxxKdTLoX4PBvThQO7QCfaxW3QkVxW9exWZg","expireIn":1482869498646}])
main_cloudrail_ready (B4A line: 70)
googledrive.loadAsString(dummy)
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.cloudrail.si.services.GoogleDrive.loadAsString(java.lang.String)' on a null object reference
  at de.donmanfred.CloudStorage.GoogleDriveWrapper.loadAsString(GoogleDriveWrapper.java:123)

This is my googleDrive_upload finished event:
B4X:
Sub googledrive_UploadFinished(destPath As String, info As String, success As Boolean)
    Log("my upload : " & success)
    Dim theToken As String = googledrive.saveAsString
    Token = theToken
    Log("Token in KVS is "& theToken)
    Starter.kvs.Put("token", Token)

Here is my googleDrive ready code:
B4X:
Sub googledrive_Ready(Success As Boolean)
    Log($"googledrive_Ready(${Success})"$)
    If Success Then
        Log("show me token: " & Token)
        If Token.Length>0 Then googledrive.loadAsString(Token)
I hope you can find what I am missing.
Thank you
 

iz0ndg

Active Member
Licensed User
Longtime User
This is my code and seems to work ....
B4X:
Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.

End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.
'   Dim dropbox As Dropbox
   Dim drive As GoogleDrive
   Dim cr As CloudRail
'   Dim places As GooglePlaces
   Dim rp As RuntimePermissions
   Dim driveToken ="" As String
End Sub

Sub Activity_Create(FirstTime As Boolean)
   'Do not forget to load the layout file created with the visual designer. For example:
   'Activity.LoadLayout("Layout1")
   cr.Initialize("CloudRail","ApiKey")
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Activity_PermissionResult (Permission As String, Result As Boolean)
   If Permission = rp.PERMISSION_WRITE_EXTERNAL_STORAGE Then
   End If
End Sub

Sub CloudRail_Ready(Success As Boolean)
   Log($"CloudRail_Ready(${Success})"$)
   File.Copy(File.DirAssets,"impostazioni",File.DirDefaultExternal,"impostazioni") ' Copy one file for example from assets to DirDefaultExternal...
   If Success Then
     If Starter.kvs.ContainsKey("token") Then
       driveToken = Starter.kvs.Getsimple("token")
     End If
     drive.Initialize("Drive","IdClient","ClientSecret")
   End If
End Sub

Sub Drive_Ready(Success As Boolean)
   Log($"Drive_Ready(${Success})"$)
   If driveToken.Length>0 Then drive.loadAsString(driveToken)
   drive.exists("/Tempfold")
End Sub

Sub Drive_DownloadFinished(success As Boolean, info As String, filePath As String, destPath As String, destFile As String)
   Log($"Drive_DownloadFinished(${destFile}->${success},${destFile},${filePath})"$)
   save_token
End Sub

Sub Drive_UploadFinished(destPath As String, info As String, success As Boolean)
   Log($"Uploaded file ${destPath}, ${info}, ${success}"$)
   save_token

   drive.download("/Tempfold/impostazioni",rp.GetSafeDirDefaultExternal("Download"),"impostazioni")
End Sub

Sub Drive_CreateFolder(folderPath As String)
   Log($"Drive folder created"$)
   save_token
   Msgbox("Cartella " & folderPath & " Creata","Drive")
   If folderPath = "/Tempfold" Then
     drive.upload(File.Combine(File.DirDefaultExternal,"impostazioni"), folderPath & "/impostazioni", File.Size(File.DirDefaultExternal,"impostazioni"), True)
   End If
End Sub

Sub Drive_Exists(Path As String, exists As Boolean)
   save_token
   If exists Then
     Msgbox("Cartella " & Path & " esistente","Drive")
     Drive_CreateFolder(Path)
   Else
     drive.createFolder("/Tempfold")
   End If
End Sub

Sub Drive_Login(Success As Boolean)
   save_token
End Sub

Sub drive_Children(directories As List, listoffiles As List)
   Log("dir:" & directories)
   Log("files :"& listoffiles)
   save_token
End Sub

Sub save_token
   Log($"Save Token"$)
   Dim t As String = drive.saveAsString
   Log("Token="&t)
   driveToken = t
   Starter.kvs.PutSimple("token", driveToken)
End Sub

The KeyValueStore initializing is in Starter Service....
 
Last edited:

Paulsche

Well-Known Member
Licensed User
Longtime User
How can I read the modification date of a file?

drive.getMetadata("/KFZdaten.db")

Sub Drive_MetaData(path As String, meta As Object)
Log($"Drive_MetaData(${path},${meta})"$)
End Sub


give a error: java.lang.NullPointerException: Attempt to invoke virtual method 'com.cloudrail.si.types.CloudMetaData com.cloudrail.si.services.GoogleDrive.getMetadata(java.lang.String)' on a null object reference
 

DonManfred

Expert
Licensed User
Longtime User
B4X:
    drive.getMetadata("/scp4.mp4")
B4X:
Sub Drive_MetaData(path As String, meta As CloudMetaData)
    Log($"Drive_MetaData(${path},${meta})"$)       
End Sub
It works for me withthe newest version...
Try this version please. Note the new Eventsignature...
 

Attachments

  • CloudRailV1.53.zip
    188.8 KB · Views: 269

Paulsche

Well-Known Member
Licensed User
Longtime User
B4X:
    drive.getMetadata("/scp4.mp4")
B4X:
Sub Drive_MetaData(path As String, meta As CloudMetaData)
    Log($"Drive_MetaData(${path},${meta})"$)      
End Sub
It works for me withthe newest version...
Try this version please. Note the new Eventsignature...

Works now great, thank you
 
Top