Unity Android build

Hi, Hope you all doing great.

We are currently trying to build an Android version of the SpecklePlayground and curious to learn how the current implementation of the project can be detached from the SpeckleManagerConnector.

I would imagine we need to take advantage of the “Personal Access Tokens”. Are there any pointers or instructions to follow?

Many thanks in advance.

1 Like

I am interested as well. Have similar question but for iOS builds.
I would assume same answer will apply.

Hi,

I’m very interested in enabling Android and IOS development with the Speckle Unity connector, as this is something we don’t do a great job currently of supporting.


You are quite correct, the best way to approach this currently, is through personal access tokens. These can be generated from your profile page.

Within Unity, you will notice that our Receiver and Sender components can be initialised optionally with an Account object. - speckle-unity/Receiver.cs at main · specklesystems/speckle-unity · GitHub

Normally this account is fetched from the AccountsManager.
But it is possible to simply create one manually, with an auth token specified.

      string token = "REPLACE WITH TOKEN";
      string serverUrl = "https://speckle.xyz";
      var account = new Account()
      {
        token = token,
        serverInfo = new ServerInfo() {url = serverUrl},
      };

I’ve given this a quick test for the Receiver component (on windows), and it appears to work fine.

But there may be a few other places where we have forgotten to expose that Account parameter.


I’ve gone and tracked this issue on our GitHub Support for Android/IOS platforms · Issue #68 · specklesystems/speckle-unity · GitHub
I have some time next week to take a look, and see what’s needed to get an Android build working. I’ll keep you updated with my progress :grin:

3 Likes

Not sure if this has changed, but something to keep in mind regarding mobile support

2 Likes

Hi all, I’ve done some testing of our Unity connector on android.
I’ve made some progress, but have run into a bit of a blocker.

The good news is, I’ve managed to get a build working nicely, There were a couple dll conflicts that were easy enough to solve. And I’ve tested a build of the Speckle Playground project on my Samsung S8+ and Quest 2.

The bad news is, I’m having trouble receiving objects. :scream:
I’m running into issues with async functions never starting (a problem we’ve faced before)

It looks like there might be differences between how UnitySynchronizationContext behaves on android :cry:

@haitheredavid How far did you get implementing UniTask in your own project?
perhaps that could solve the async issue on android.

@Jedd I’ve actually ditched the UniTasks for any send / receive calls. The package declares there is no overhead or allocation needed for converting a Task to UniTasks but whenever I did the conversion with something like Operations.Receive it would clog up all my CPU’s. I came to the conclusion that I would only use unitask for unity based methods.

I don’t recall having any issues with unity and awaitable calls when building to android, but I wouldn’t be surprised if there is some sort of catch. Were you able to send objects? Would be curious to know where the operation breaks, I suspect it might have to do with some sort of HTTP call.

1 Like

Hi,

Thanks for looking into this. We have made some progress our end as well. We did manage to build and read streams on Android.

Unfortunately, we’ve run into another issue. Send and receive operations throw a “IOException: Read-only file system”.

Have you encountered that before? any ideas how to solve this?

1 Like

@Jedd
Correction… Send operations actually getting executed correctly. The above error is thrown on Receive operations only!

1 Like

Hi,

I can explain why this error might be happening, suggest a few quick and dirty fixes, and then perhaps discuss some more long term fixes to this issue.


This issue appears to be related to SQLite transports.
This is the transport we use (by default) to cache objects on your local machine (Local Transport).

You can read more about what Transports are here, but in a nut shell, transport is an interface to a data store (of speckle objects). We have a few different transports for different needs (server ones for interfacing with a server, and local ones (memory, disk, SQLite).

Clearly, from your error, SQLite transports aren’t working nicely (maybe because they are looking for a database file in windows appdata directory.)

It’s not too surprising that this doesn’t work with Android, so I imagine this is what you are running into.


A quick and dirty fix, would be to specify your own localTransport when calling Operations.Receive. That way, it won’t try and use the “default” SQLite one.


        var transport = new ServerTransport(Client.Account, StreamId);
        var localCache = new MemoryTransport();
            
        var @base = await Operations.Receive(
          objectId,
          remoteTransport: transport,
          localTransport: localCache,
          onErrorAction: OnErrorAction,
          onProgressAction: OnProgressAction,
          onTotalChildrenCountKnown: OnTotalChildrenCountKnown,
          disposeTransports: true
        );

Although, recreating a new memory transport for every receive operation is quite wasteful, and pointless as a cache. So you may want to consider making that localCache a field so it gets reused.


However, this isn’t an ideal situation.

I can think of a few better options we could explore:

  1. Get SQlite transports working on android
  2. If SQLite transports flat-out don’t work on android, then they shouldn’t be the default local transport for android (duh!)
  3. Provide a way to explicitly specify “no cache”, e.g. implement a “null”/“non” transport.

Hopefully with my “quick and dirty” suggestion, you are able to get something working.
I will continue some tests my end.
Please do let me know if you have any difficulties, this exploratory feedback is super valuable to us, and hopefully will allow us to support non-desktop platforms going forward.

2 Likes

Hi @Jedd, has anything involving this received a more permanent fix? I’m merely trying to build a bare bones ARCore app using a Speckle-received Revit model that was already brought into the Unity editor, and I get the errors below that seem to involve the SQLite, and this prevents me from building the APK in the first place. I can confirm that I was able to build the app before bringing in anything Speckle:

Building C:\Users\travis.rothbloom\Documents\BasicARCoreProject\Library\Bee\artifacts\unitylinker_xy1a.traceevents failed with output:

C:\Program Files\Unity\Hub\Editor\2021.3.17f1\Editor\Data\il2cpp\build\deploy\UnityLinker.exe --search-directory=C:/Users/[travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed](https://travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed) --out=Library/Bee/artifacts/Android/ManagedStripped --include-link-xml=C:/Users/[travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed\TypesInScenes.xml](https://travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/TypesInScenes.xml) --include-link-xml=C:/Users/[travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed\SerializedTypes.xml](https://travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/SerializedTypes.xml) --include-link-xml=C:/Program Files/Unity/Hub/Editor/2021.3.17f1/Editor/Data/PlaybackEngines/AndroidPlayer/Tools/AndroidNativeLink.xml --include-directory=C:/Users/[travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed](https://travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed) --profiler-report --profiler-output-file=C:/Users/[travis.rothbloom/Documents/BasicARCoreProject/Library/Bee/artifacts/unitylinker_xy1a.traceevents](https://travis.rothbloom/Documents/BasicARCoreProject/Library/Bee/artifacts/unitylinker_xy1a.traceevents) --dotnetprofile=unityaot-linux --dotnetruntime=Il2Cpp --platform=Android --use-editor-options --enable-engine-module-stripping --engine-modules-asset-file=C:/Program Files/Unity/Hub/Editor/2021.3.17f1/Editor/Data/PlaybackEngines/AndroidPlayer/modules.asset --editor-data-file=C:/Users/[travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/EditorToUnityLinkerData.json](https://travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/EditorToUnityLinkerData.json) --include-unity-root-assembly=C:/Users/[travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/Speckle.ConnectorUnity.NativeCache.dll](https://travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/Speckle.ConnectorUnity.NativeCache.dll) --include-unity-root-assembly=C:/Users/[travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/Unity.XR.Management.dll](https://travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/Unity.XR.Management.dll) --include-unity-root-assembly=C:/Users/[travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/Unity.XR.ARCore.dll](https://travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/Unity.XR.ARCore.dll) --include-unity-root-assembly=C:/Users/[travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/Speckle.ConnectorUnity.Wrappers.dll](https://travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/Speckle.ConnectorUnity.Wrappers.dll) --include-unity-root-assembly=C:/Users/[travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/Speckle.ConnectorUnity.Components.dll](https://travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/Speckle.ConnectorUnity.Components.dll) --include-unity-root-assembly=C:/Users/[travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/Unity.XR.ARFoundation.dll](https://travis.rothbloom/Documents/BasicARCoreProject/Temp/StagingArea/Data/Managed/Unity.XR.ARFoundation.dll) --print-command-line --enable-analytics

Fatal error in Unity CIL Linker

Mono.Linker.LinkerFatalErrorException: ILLink: error IL1005: Microsoft.Data.Sqlite.SqliteConnection..cctor(): Error processing method 'Microsoft.Data.Sqlite.SqliteConnection..cctor()' in assembly 'Microsoft.Data.Sqlite.dll'

---> System.InvalidOperationException: No action for the assembly SQLitePCLRaw.batteries_v2, Version=2.1.4.1835, Culture=neutral, PublicKeyToken=8226ea5df37bcae9 defined
at Mono.Linker.AnnotationStore.GetAction(AssemblyDefinition assembly)
at Mono.Linker.Steps.MarkStep.IsFullyPreserved(TypeDefinition type)
at Mono.Linker.Steps.MarkStep.MarkType(TypeReference reference, DependencyInfo reason, IMemberDefinition sourceLocationMember)
at Mono.Linker.Steps.MarkStep.MarkTypeVisibleToReflection(TypeReference reference, DependencyInfo reason, IMemberDefinition sourceLocationMember)
at Mono.Linker.Dataflow.ReflectionMethodBodyScanner.<>c__DisplayClass20_4.<HandleCall>b__7()
at Mono.Linker.Dataflow.ReflectionMethodBodyScanner.HandleCall(MethodBody callingMethodBody, MethodReference calledMethod, Instruction operation, ValueNodeList methodParams, ValueNode& methodReturnValue)
at Mono.Linker.Dataflow.MethodBodyScanner.HandleCall(MethodBody callingMethodBody, Instruction operation, Stack`1 currentStack)
at Mono.Linker.Dataflow.MethodBodyScanner.Scan(MethodBody methodBody)
at Mono.Linker.Dataflow.ReflectionMethodBodyScanner.ScanAndProcessReturnValue(MethodBody methodBody)
at Unity.Linker.Steps.UnityMarkStep.MarkReflectionLikeDependencies(MethodBody body, Boolean requiresReflectionMethodBodyScanner)
at Mono.Linker.Steps.MarkStep.MarkMethodBody(MethodBody body)
at Unity.Linker.Steps.UnityMarkStep.MarkMethodBody(MethodBody body)
at Mono.Linker.Steps.MarkStep.ProcessMethod(MethodDefinition method, DependencyInfo& reason)
at Unity.Linker.Steps.UnityMarkStep.ProcessMethod(MethodDefinition method, DependencyInfo& reason)
at Mono.Linker.Steps.MarkStep.ProcessQueue()

--- End of inner exception stack trace ---
at Mono.Linker.Steps.MarkStep.ProcessQueue()
at Mono.Linker.Steps.MarkStep.ProcessPrimaryQueue()
at Mono.Linker.Steps.MarkStep.Process()
at Mono.Linker.Steps.MarkStep.Process(LinkContext context)
at Unity.Linker.Steps.UnityMarkStep.Process(LinkContext context)
at Unity.Linker.UnityPipeline.ProcessStep(LinkContext context, IStep step)
at Mono.Linker.Pipeline.Process(LinkContext context)
at Unity.Linker.UnityDriver.UnityRun(Boolean noProfilerAllowed, ILogger customLogger)
at Unity.Linker.UnityDriver.RunDriverWithoutErrorHandling(ILogger customLogger, Boolean noProfilerAllowed)
at Unity.Linker.UnityDriver.RunDriver()

UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)

Right now, our C# core is not compatible with Unity’s AOT compilation.

We have a ticket to investigate what we would need to do to support. But looking at the restrictions, it looks like this may be a lot of work on our end.
I’ll keep you updated if we manage to figure anything out. But unlikely to see support anytime soon.

2 Likes

@travis-rothbloom Would you be able to work around this limitation? are you able to compile for mono or do you require il2cpp?
What platforms do you hope to target? just android or others aswell?

I tried building with mono and while that succeeded, my Android phone said “You can’t install the app on this device” with no further detail.

Do you get any build warnings?

Perhaps you could try following some of the troubleshooting steps here.
e.g.

Unable to install APK to device

This error can be caused by:

  • Installing to an incompatible device.
  • Installing to a device running a version of Android lower than the Minimum API Level in your Player settings.

There may also be some android SDK configuration you may wish to double check. see Unity - Manual: Android requirements and compatibility


Another useful thing you could test is with a blank unity project and the same build target/settings, does it then work? or are you seeing the same issue even on a blank project?