android preview + uno code = doesnt work

Hello guys,
Dear Fuse Team,

I figured out that my android preview doesnt work with projects I created android specific uno code for.
Thats really frustrating, because I can not debug it without my android preview.
What is the result?
Always when I try to preview it on my android device, which is connected, the preview app starts and it stucks at “Connecting to computer…”. After some minutes there comes up the screen “Failed to connect” with some informations about “reached end of stream” and “Connection timed out”.

Here are the basic informations to my configuration:

  • I have used two different android devices, two different networks, two different windows computers.
  • The android preview works very well, in projects wheres just .ux and javascript involved.
  • I can ping the android devices from the computers and I can ping the computers from the android devices.

Please take a look at the community package for creating sharing sheets. Its exactly the same result with my own written uno code and with every other project where are uno and java files involved.

After one entire weekend with struggles I can just explain it for me, that theres a bug in the android preview due to the new versions.

I hope someone can help me, thanks.

Hi, the problem is probably that you have something in your project that makes it not compile for .net. When previewing, we need a working .net build as well as a device build, in order for the preview host to understand the project.

In the current version of Fuse, there are a few issues where these types of errors never reach the user. This has been fixed for an upcoming revamp of Fuse, but for now there are a few workarounds you can try in order to see the actual error:

  1. Make sure the project works in normal fuse preview (not on device)
  2. (If 1. is not enough) See if fuse host-preview --compile-only shows any additional errors

Thats the output when I try both

C:\Users\bened\Documents\Fuse\testproject>fuse preview
Fuse 0.33.0 (build 10195)
Build started: FullCompile
Configuring (1.3 s)
Compiling syntax tree (4.7 s)
Generating code and data
ERROR: Failed to compile .NET type 'Service': The invoked member is not supported before the type is created.
(16.2 s)

Build completed in 22.24 seconds
    1 error
Build ended
fuse: Failed to compile project

C:\Users\bened\Documents\Fuse\testproject>fuse host-preview --compile-only
fuse: The specified path does not appear to be a .unoproj file

C:\Users\bened\Documents\Fuse\testproject>

The same result with the community package about sharesheets

We’re digging a bit further into this and will get back to you, but for now:
Do things work out better if you move the ForeignInclude’s inside the class?

I’m sorry, I forgot an important detail: When you do fuse host-preview --compile-only, you have to include the name of the project file:

fuse host-preview --compile-only ProjectName.unoproj

But if your project doesn’t even work in local preview, we need to solve that first anyway.

OK guys, sorry for the late reply…

it seems, that the local preview is able to render, if I put the ForeignInclude’s inside the class… it looks like this:

...
 static object StopService(Context c, object[] args)
    {
        if defined(Android) StopServiceJ();

        return null;
    }

    
    [Require("AndroidManifest.ApplicationElement", "<service android:name=\".ServiceClass\" />")]
    [ForeignInclude(Language.Java, "android.content.Intent", "com.example.bened.firstandroidproj.ServiceClass")]
    [ForeignInclude(Language.Java, "android.content.Context")]
    [Foreign(Language.Java)]
    static extern(Android) void StartServiceJ()
    @{
       Context context = com.fuse.Activity.getRootActivity();
        context.startService(new Intent(context, ServiceClass.class));
    @}
...

However, in this configuration its not possible to render the Android preview, because it says that

Configuring (3.8 s)
Compiling syntax tree
C:\Users\bened\Documents\Fuse\testproject\Service.uno(45.6): E0000: Attribute [Uno.Compiler.ExportTargetInterop.ForeignInclude] can only be used on 'class'
C:\Users\bened\Documents\Fuse\testproject\Service.uno(46.2): E0000: Attribute [Uno.Compiler.ExportTargetInterop.ForeignInclude] can only be used on 'class'
(4.2 s)

Build completed in 8.12 seconds
    2 errors

# Build complete.

But if I put the two ForeignInclude’s back on top of the class, it seems to be able to compile. The only thing, which still is inside the class is the manifest require. It also starts the preview on the device properly and my both buttons do appear. But the functionality - my started background service - is missing, the both buttons simply do nothing. Inside the loaded java class are several Toast messages shown up. The code works on native java environment, but not wrapped in uno.
Looks interesting though…

Hey Benny!

We are aware of the problem with ForeignInclude in local preview and are working on a fix. The issue is that the compiler backend used in preview erroneously compiles the ForeignInclude attribute before the Language enum has been compiled for some reason, which leads to the error you’re seeing. In the meantime you can use this workaround: stick an extern(Android) (or iOS depending on your target) on the ForeignInclude like so:

[extern(Android) ForeignInclude(Language.Java, "android.content.Intent", "com.example.bened.firstandroidproj.ServiceClass")]

Then you should be able to use it on the class.

We will probably need more information to understand why your background service doesn’t work. I’m assuming you’re calling the StartServiceJ function that you showed above. What are you using to detect whether the service is running? Perhaps you can do some logging to find out where it goes wrong?

hehehe it works now!! :slight_smile: the extern(Android) made the difference. The App starts now in Android preview, thank you very much.

But unfortunately I dont have the the desired result. My service starts and toasts the message, also in background and again after my period of 2 seconds. But since I made my service running in START_STICKY mode it unfortunately kills the process when I kill the app. But I want the process and the service to restart when the app is killed, thats what the sticky service is supposed to do.
Thats my used java code, inside the service java class:

package com.example.bened.firstandroidproj;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.widget.Toast;

/**
 * Created by benny on 04.02.2017.
 */

public class ServiceClass extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    Context cont;
    boolean run = true;
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        
        cont = this;

        Toast.makeText(this,"heyyy Im running", Toast.LENGTH_SHORT).show();
        final Handler handler = new Handler();
        final Runnable r = new Runnable() {
            public void run() {

                Toast.makeText(cont,"...and again", Toast.LENGTH_SHORT).show();
                if(run) {
                    handler.postDelayed(this, 2000);
                }
            }
        };
        handler.postDelayed(r, 1000);


        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        run = false;
        Toast.makeText(cont,"STOP!", Toast.LENGTH_SHORT).show();
    }
}

I also tried to uncomment the onDestroy method, but it doesnt help anyway.
Is there a way to prevend the main thread to kill everything when fuse gives the destroying command?