processing / processing-android

Processing mode and core library to create Android apps with Processing
http://android.processing.org
779 stars 293 forks source link

Building from command line fails #158

Open Loadus opened 8 years ago

Loadus commented 8 years ago

I get an error about Java mode when I try to build from the command line. I use Sublime Text to build the .apk, and this might just be a configuration error on my end but posting this just in case. Note - this works with earlier versions (last one tested was 3.0a5, builds fine). I can almost fix this, but I'm not exactly sure on what's going on:

$ processing-android --sketch="/home/loadus/Dropbox/inkbrush/processing/3.0/InkBrush/InkBrush.pde" --output="/home/loadus/Dropbox/inkbrush/processing/3.0/InkBrush/android/" --target=debug --run --force

APPDIR=/home/loadus/development/processing
DIR=/home/loadus/development/processing/java
L=rt.jar
LIB=/home/loadus/development/processing/java/lib/rt.jar
L=tools.jar
LIB=
JDKCP=/home/loadus/development/processing/java/lib/rt.jar
SUCCESS=0
DIR=/usr/lib/jvm/java-8-oracle/jre/bin/../..
L=rt.jar
LIB=/usr/lib/jvm/java-8-oracle/jre/bin/../../jre/lib/rt.jar
L=tools.jar
LIB=/usr/lib/jvm/java-8-oracle/jre/bin/../../lib/tools.jar
JDKCP=/usr/lib/jvm/java-8-oracle/jre/bin/../../jre/lib/rt.jar:/usr/lib/jvm/java-8-oracle/jre/bin/../../lib/tools.jar
SUCCESS=1
CLASSPATH=/usr/lib/jvm/java-8-oracle/jre/bin/../../jre/lib/rt.jar:/usr/lib/jvm/java-8-oracle/jre/bin/../../lib/tools.jar:/home/loadus/development/processing/lib/AndroidMode.jar:/home/loadus/development/processing/lib/ant-launcher.jar:/home/loadus/development/processing/lib/ant.jar:/home/loadus/development/processing/lib/jna.jar:/home/loadus/development/processing/lib/pde.jar:/home/loadus/development/processing/core/library/core.jar:/home/loadus/development/processing/core/library/gluegen-rt-natives-linux-amd64.jar:/home/loadus/development/processing/core/library/gluegen-rt-natives-linux-armv6hf.jar:/home/loadus/development/processing/core/library/gluegen-rt-natives-linux-i586.jar:/home/loadus/development/processing/core/library/gluegen-rt-natives-macosx-universal.jar:/home/loadus/development/processing/core/library/gluegen-rt-natives-windows-amd64.jar:/home/loadus/development/processing/core/library/gluegen-rt-natives-windows-i586.jar:/home/loadus/development/processing/core/library/gluegen-rt.jar:/home/loadus/development/processing/core/library/jogl-all-natives-linux-amd64.jar:/home/loadus/development/processing/core/library/jogl-all-natives-linux-armv6hf.jar:/home/loadus/development/processing/core/library/jogl-all-natives-linux-i586.jar:/home/loadus/development/processing/core/library/jogl-all-natives-macosx-universal.jar:/home/loadus/development/processing/core/library/jogl-all-natives-windows-amd64.jar:/home/loadus/development/processing/core/library/jogl-all-natives-windows-i586.jar:/home/loadus/development/processing/core/library/jogl-all.jar
PATH=/usr/lib/jvm/java-8-oracle/jre/bin/../bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/etc/OpenCL/java_native:/home/loadus/development/processing

Error: A JNI error has occurred, please check your installation and try again

Exception in thread "main" java.lang.NoClassDefFoundError: processing/mode/java/JavaMode
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
    at java.lang.Class.getMethod0(Class.java:3018)
    at java.lang.Class.getMethod(Class.java:1784)
    at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)

Caused by: java.lang.ClassNotFoundException: processing.mode.java.JavaMode

    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 19 more
[Finished in 0.1s with exit code 1]
[cmd: ['processing-android', '--sketch=/home/loadus/Dropbox/inkbrush/processing/3.0/InkBrush', '--output=/home/loadus/Dropbox/inkbrush/processing/3.0/InkBrush/android', '--target=debug', '--run', '--force']]
[dir: /home/loadus/Dropbox/inkbrush/processing/3.0/InkBrush]
[path: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/etc/OpenCL/java_native:/home/loadus/development/processing]
Loadus commented 8 years ago

Running this in a clean installation of Processing, the problem persists. Adding JavaMode.jar and AndroidMode.jar to the classpath of processing-android throws this:

Exception in thread "main" java.lang.NoClassDefFoundError: antlr/RecognitionException
    at processing.mode.android.Commander.execute(Commander.java:216)
    at processing.mode.android.Commander.main(Commander.java:91)
Caused by: java.lang.ClassNotFoundException: antlr.RecognitionException
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 2 more

Also there's a very scary part in https://github.com/processing/processing-android/blob/master/src/processing/mode/android/Commander.java : 185 a hardcoded location for the AndroidMode library (I have no idea if this has any effect on the build process, I'm just generally frightened about hardcoded values).

I've battled with this before (http://forum.processing.org/two/discussion/7711/building-for-android-from-sublime) and would love to bring this into conclusion - I'm currently doing some modifications to the build script so it would work on a clean Processing 3.0 installation that has Android Mode installed.

Loadus commented 8 years ago

I did a test build where I changed

Commander.java:185

    androidMode = (AndroidMode) ModeContribution.load(null, Platform.getContentFile("modes/android"),
        "processing.mode.android.AndroidMode").getMode();

to

    androidMode = (AndroidMode) ModeContribution.load(null, Platform.getContentFile(Preferences.getSketchbookPath() + "/modes/AndroidMode/mode"),
        "processing.mode.android.AndroidMode").getMode();

EDIT: ups, this is supposed to be

    androidMode = (AndroidMode) ModeContribution.load(null, new File(Preferences.getSketchbookPath() + "/modes/AndroidMode/mode"),
        "processing.mode.android.AndroidMode").getMode();

just to see if there was a change, but build ends with

Exception in thread "main" java.lang.NoClassDefFoundError: antlr/RecognitionException
    at processing.mode.android.Commander.execute(Commander.java:219)
    at processing.mode.android.Commander.main(Commander.java:91)
Caused by: java.lang.ClassNotFoundException: antlr.RecognitionException

which points to

219     AndroidBuild build = new AndroidBuild(sketch, androidMode);

EDIT: Ssssstupid me. The path to antlr.jar was missing. That's what the error meant. *puts on the cone of shame*

Processing IDE itself builds the .apk with no problems and sends it off to the device. It's totally rolling with it.

Loadus commented 8 years ago

Almost got it to build, the compile exited with two errors:

12. ERROR in /tmp/android843914374061291639sketch/src/processing/test/inkbrush/MainActivity.java (at line 26)
    FragmentTransaction ft = getFragmentManager().beginTransaction();
                             ^^^^^^^^^^^^^^^^^^
The method getFragmentManager() is undefined for the type MainActivity
----------
13. ERROR in /tmp/android843914374061291639sketch/src/processing/test/inkbrush/MainActivity.java (at line 29)
    fragment = (PApplet) getFragmentManager().findFragmentByTag(MAIN_FRAGMENT_TAG);
                         ^^^^^^^^^^^^^^^^^^
The method getFragmentManager() is undefined for the type MainActivity

I had to add direct paths to various libs in processing-android (mainly because I don't know how to ask for Processing to provide the paths):

for LIB in "$APPDIR"/modes/java/mode/*.jar; do
  CLASSPATH="$CLASSPATH"${CLASSPATH:+:}"$LIB"
done

  CLASSPATH="$CLASSPATH"${CLASSPATH:+:}"/home/loadus/sk3tchbook/modes/AndroidMode/mode/AndroidMode.jar"  
  CLASSPATH="$CLASSPATH"${CLASSPATH:+:}"/home/loadus/development/android-sdk-linux/platforms/android-17/android.jar"

and I had to copy android-core.zip to /modes/android in Processing's folder.

And let me know if this is an issue no one cares about so I'll know when to stop. I'd really love to get this working as I do my coding on external editors.

EDIT: The temp build project sets target=android-10 in project.properties and Fragment is API 11. How can this be changed?

Loadus commented 8 years ago

Ok, so here's the rundown:

processing-android build script

Android Mode source:

AndroidBuild.java

50
  static String sdkName = "4.0.3";
  static String sdkVersion = "15";  // Android 4.0.3

Here is the modified build script (this can be done waaay more elegantly with Processing providing the needed paths)

#!/bin/sh

# This script runs Processing, using the JDK in the Processing 
# installation directory if possible.

# If no JDK was installed with Processing then the script tries to use 
# the preferred Java version of the machine, i.e. what is executed 
# by the "java" console command. This must be a Sun JDK (for details, see
# http://processing.org/reference/environment/platforms.html#java).

# In order to run Processing with an already installed JDK that is *not* 
# the preferred Java version of the machine, create a symlink named "java" 
# in the Processing installation directory that points to the JDK home
# directory.

# Thanks to Ferdinand Kasper for this build script. [fry]

# Target version
ANDROID_VERSION="17"

# Your sketchbook location
SKETCHBOOK_LOCATION="complete_path_to_your_sketchbook"

# JARs required from JDK (anywhere in/below the JDK home directory)
JDKLIBS="rt.jar tools.jar"

# Set this to non-zero for logging
LOGGING=1

# Logs name and value of a variable to stdout if LOGGING is non-zero.
# Expects the variable name as parameter $1.
log() {
  if [ $LOGGING -ne 0 ]; then
    eval echo $1=\$$1
  fi
}

# Locates JDKLIBS in a directory and its subdirectories and saves their
# absolute paths as list to JDKCP. Expects the directory as parameter $1.
# Sets SUCCESS to 1 if all libraries were found, to 0 otherwise.
make_jdkcp() {
  # Back out of JRE directory if apparently located inside a JDK
  if [ -f "$1/../bin/java" ]; then
    DIR="$1/.."
  else
    DIR="$1"
  fi
  log DIR

  JDKCP=
  SUCCESS=1

  # Locate JDKLIBS
  for L in $JDKLIBS; do
    # Locate only the first library with a matching name
    LIB=`find "$DIR" -name $L 2>/dev/null | head -n 1`
    log L
    log LIB

    # Library found?
    if [ -n "$LIB" ]; then
      JDKCP="$JDKCP"${JDKCP:+:}"$LIB"
    else
      SUCCESS=0
    fi
  done

  log JDKCP
}

# Get absolute path of directory where this script is located
APPDIR=`readlink -f "$0"`
APPDIR=`dirname "$APPDIR"`
log APPDIR

# Try using a local JDK from the same directory as this script
JDKDIR=`readlink -f "$APPDIR/java"`
make_jdkcp "$JDKDIR"
log SUCCESS

# Local JDK found?
if [ $SUCCESS -ne 1 ]; then
  # No, try using the preferred system JRE/JDK (if any)
  JDKDIR=`which java` && JDKDIR=`readlink -e "$JDKDIR"` && JDKDIR=`dirname "$JDKDIR"`/..
  make_jdkcp "$JDKDIR"
  log SUCCESS
fi

# Add all required JARs to CLASSPATH
CLASSPATH="$CLASSPATH"${CLASSPATH:+:}"$JDKCP"

for LIB in "$APPDIR"/lib/*.jar; do
  CLASSPATH="$CLASSPATH"${CLASSPATH:+:}"$LIB"
done

for LIB in "$APPDIR"/core/library/*.jar; do
  CLASSPATH="$CLASSPATH"${CLASSPATH:+:}"$LIB"
done

for LIB in "$APPDIR"/modes/java/mode/*.jar; do
  CLASSPATH="$CLASSPATH"${CLASSPATH:+:}"$LIB"
done

  CLASSPATH="$CLASSPATH"${CLASSPATH:+:}$SKETCHBOOK_LOCATION"/modes/AndroidMode/mode/AndroidMode.jar"
  CLASSPATH="$CLASSPATH"${CLASSPATH:+:}$ANDROID_SDK"/platforms/android-"$ANDROID_VERSION"/android.jar"

export CLASSPATH
log CLASSPATH

# Make all JDK binaries available in PATH
export PATH="$JDKDIR/bin":"$PATH"
log PATH

current_name=`basename $0`
cmd_name='processing-android'

if [ $current_name = $cmd_name ]
then
    java processing.mode.android.Commander "$@"
else
  # Start Processing in the same directory as this script
  if [ "$1" ]; then
    SKETCH=`readlink -f $1`
  else
    SKETCH=
  fi
  cd "$APPDIR"

  java processing.app.Base "$SKETCH" &
fi

I'm going to dive into the getContentFile() method and see if I can modify it without borking the project. Dude needs a map.

Loadus commented 8 years ago

I made a couple of pull requests for changes to allow commandline build working again. I'm not that happy about the absolute path mod, it's really dirty. https://github.com/Loadus/processing-android/pulls

omerjerk commented 8 years ago

You opened the pull requests in your repository. Please open them here for us to merge.

Loadus commented 8 years ago

Problem is, I'm not exactly sure how to do that. : D

EDIT: Well, something happened. The pulls need heavy review though.

codeanticode commented 8 years ago

I merged https://github.com/processing/processing-android/pull/161, which seemed reasonable. The other two (https://github.com/processing/processing-android/pull/160, https://github.com/processing/processing-android/pull/162) need more discussion.