I have a Cordova project created using Visual Studio 2015's Tools for Apache Cordova. We're trying to create a plugin that uses an external library, and that library depends on various things such as Google's location services. I've found that they go in a .gradle file, but have no idea how to get them in that file using TACO. I can do it manually, but VS regenerates the .gradle file every time the project's built.
I'm new to TACO, so it may be I'm missing something.
Very common problem when starting out with Cordova Plugins. I've struggled with this in the past. Start by reading this. You need to add some entries to your plugin.xml file. In that file you should have a section for each platform you support. You should also not be modifying the platform/android/build.gradle file directly. Make a separate one which will eventually get it's contents appended to your platform/android/build.gradle using <framework>.
<platform name="android">
</platform>
In platforms add something similar to match your features:
Permissions docs
<config-file target="AndroidManifest.xml" parent="/*">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
....
</config-file>
External Libs docs
<framework src="src/android/build.gradle" custom="true" type="gradleReference" />
<source-file src="lib/android/sample-android-sdk/sample.jar" custom="true" target-dir="lib" />
Related
I am trying to integrate the HockeyApp Android SDK in its latest version 4.1.2 into our Qt Android app. I don't know a lot about Android development or Java in general - nor any Qt or HockeyApp internals.
There is some general official documentation on including third party Android (i.e. Java) libraries into a Qt project; however, it mentions a "Create AndroidManifest.xml button in the Deployment settings" which does not exist in the current Qt Creator 4.2.0 version, so I am unsure as to how outdated this documentation is or what parts possibly still apply.
HockeyApp documentation only covers "typical Android development" using Android Studio and their support is not supportive.
On a side note, integrating the HockeyApp iOS SDK took just a couple of hours and was mostly a matter of writing some Objective C bridge code.
Step 1: Add the SDK to the project
First approach
I tried to follow the above documentation and added the unzipped HockeySDK-Android-4.1.2 folder and a project.properties file with contents
android.library.reference.1=HockeySDK-Android-4.1.2/libs/
to a project folder; I also set ANDROID_PACKAGE_SOURCE_DIR in <my project>.pro to that project folder.
Problem: The androiddeployqt build step issues an error message (wrapped for readability)
Error: <path to build folder>/android-build/HockeySDK-Android-4.1.2/libs
is not a valid project (AndroidManifest.xml not found).
but continues anyway and finally fails with an error message (also wrapped for readability)
BUILD FAILED
/opt/Android/android-sdk-macosx/tools/ant/build.xml:573:
HockeySDK-Android-4.1.2/libs/ resolve to a path
with no project.properties file for project <path to build folder>/android-build
Running androiddeployqt with a --verbose switch adds significantly more output, but zero useful information.
Second approach
The downloaded HockeyApp Android SDK zip archive contains - besides some documentation - a file libs/HockeySDK-4.1.2.aar; from this response and this comment, I gather the AAR format is simply a zip archive that, among others, contains an AndroidManifest.xml file. I unzipped libs/HockeySDK-4.1.2.aar in place, then removed it; now the first error message in the build is gone.
Problem: The build fails with
BUILD FAILED
/opt/Android/android-sdk-macosx/tools/ant/build.xml:597:
The following error occurred while executing this line:
/opt/Android/android-sdk-macosx/tools/ant/build.xml:649:
The following error occurred while executing this line:
/opt/Android/android-sdk-macosx/tools/ant/build.xml:655:
<path to build folder>/android-build/HockeySDK-Android-4.1.2/libs/src does not exist.
Again, adding running --verbose to androiddeployqt adds nothing but noise. Looking into the build.xml locations mentioned doesn't help either.
Update:
I tried simply creating the missing folder from the error message; now the build fails as follows:
-dex:
[dex] input: <path to build folder>/android-build/bin/classes
[dex] input: <path to build folder>/android-build/HockeySDK-Android-4.1.2/libs/bin/classes.jar
[dex] input: <path to build folder>/android-build/libs/QtAndroid-bundled.jar
[dex] input: <path to build folder>/android-build/libs/QtAndroidBearer-bundled.jar
[dex] Pre-Dexing <path to build folder>/android-build/libs/QtAndroid-bundled.jar -> QtAndroid-bundled-a06280f40655c27b25038380a4d7f67c.jar
[dex] Pre-Dexing <path to build folder>/android-build/libs/QtAndroidBearer-bundled.jar -> QtAndroidBearer-bundled-a69fa323dbfa477411ea082423128813.jar
[dex] Converting compiled files and external libraries into <path to build folder>/android-build/bin/classes.dex...
[dx]
[dx] UNEXPECTED TOP-LEVEL EXCEPTION:
[dx] java.io.FileNotFoundException: <path to build folder>/android-build/HockeySDK-Android-4.1.2/libs/bin/classes.jar (No such file or directory)
[dx] at java.util.zip.ZipFile.open(Native Method)
[dx] at java.util.zip.ZipFile.<init>(ZipFile.java:219)
[dx] at java.util.zip.ZipFile.<init>(ZipFile.java:149)
[dx] at java.util.zip.ZipFile.<init>(ZipFile.java:163)
[dx] at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:244)
[dx] at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
[dx] at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
[dx] at com.android.dx.command.dexer.Main.processOne(Main.java:677)
[dx] at com.android.dx.command.dexer.Main.processAllFiles(Main.java:574)
[dx] at com.android.dx.command.dexer.Main.runMonoDex(Main.java:311)
[dx] at com.android.dx.command.dexer.Main.run(Main.java:277)
[dx] at com.android.dx.command.dexer.Main.main(Main.java:245)
[dx] at com.android.dx.command.Main.main(Main.java:106)
[dx] 1 error; aborting
BUILD FAILED
/opt/Android/android-sdk-macosx/tools/ant/build.xml:888: The following error occurred while executing this line:
/opt/Android/android-sdk-macosx/tools/ant/build.xml:890: The following error occurred while executing this line:
/opt/Android/android-sdk-macosx/tools/ant/build.xml:902: The following error occurred while executing this line:
/opt/Android/android-sdk-macosx/tools/ant/build.xml:283: null returned: 1
I obviously can not just make up some classes.jar file, but there is one single file with that name in <path to build folder>/android-build/HockeySDK-Android-4.1.2/libs, so I can create the missing bin folder and create a symlink in it to ../classes.jar.
The build now succeeds. Step 1 complete.
Step 2: Use the SDK in the project
Going back to the corresponding HockeyApp documentation, I gather I need to modify some code that looks similar to
public class YourActivity extends Activity
...
There is one single occurrence of such code in the project in <path to build folder>/android-build/src/org/qtproject/qt5/android/bindings/QtActivity.java:
public class QtActivity extends Activity
...
That file is copied there by the androiddeployqt tool (part of the Qt SDK) from its source folder inside the Qt SDK at $QTDIR/src/android/java, i.e. /opt/Qt/Qt_5.7.1/5.7/android_armv7/src/android on my machine.
Looking at the androiddeployqt source code, I see there is no way (e.g. by means of a command line parameter) to change the source folder these .java files are taken from, so it is not possible to provide my own set of files and have androiddeployqt copy that instead. Hence, in order to make this work, I must either extend / fix androiddeployqt functionality (sorry, I won't touch that code - yuck!) or modify the copied files at their source directly - which then obviously affects all projects build with that Qt SDK instance.
As a third approach, I could try patching the Java sources after androiddeployqt copied them to the build folder. Unfortunately, this not only makes the development and build workflow absurdly painful; it is also made entirely impossible by the androiddeployqt "one tool does everything" design fail (see below): There is no point in time in the build process where the Java sources exist in the project and the .apk package has not been built yet. I thought the androiddeployqt --no-build parameter would enable that:
--no-build: Do not build the package, it is useful to just install
a package previously built.
but "building" here refers to building the Qt / Java bridge code, not the actual app, so that parameter turns out to be pretty much useless for the task at hand; the build fails with this message - which by itself are a bug as the .apk file from the message does not exist and thus the Android package build was not successful:
Android package built successfully in 1.011 ms.
-- File: <path to build folder>/android-build//bin/QtApp-release-unsigned.apk
Sure, I could copy the sources elsewhere, patch and copy them manually to their final destination, but I think this is where I draw the line.
Actually, looking at the androiddeployqt source code is where the buck stops. Too much time has already been wasted trying to get dysfunctional tools to work:
I will not comment on how smart it is to write a build tool in C++ in the first place - in a single, ~3000 line main.cpp file
I will not comment on the practice of hardcoding the src/android/java path (and many other paths) in the androiddeployqt sources not once, but multiple times - instead of a const QString that at least prepares appropriate (i.e. external) tool configuration
I will not comment on how smart it is to violate the ~50 year old best practice of one tool, one purpose - and duplicate large amounts of functionality provided by Qt, Android or Java tools, such as building, signing, deploying, installing packages, etc.
However, the fact that this tool has made it past code review into a number of major Qt release is nothing short of frightening - and probably a good indicator that it's time to consider dropping Qt as a technology in general
While I am writing this, the Qt 5.8.0 installation keeps freezing, maxing out one CPU core - and has been doing so for the last ~12 hours. I rest my case.
My questions
has anyone had any success with Qt, Android and HockeyApp ?
does anyone have any hints / pointers / wild guesses as to what is wrong here ?
no further questions; I've seen enough
Step 3: Call SDK Java code from C++
(cancelled due to brickwall in step 2)
Answering my own question:
Using the HockeyApp SDK with Qt on Android is not possible without either patching Qt SDK tool source code or Qt SDK Java template source files.
In fact, from what I gather, it is not possible to use any third party libraries with Qt on Android if they require Java source code modification.
FWIW this is an AndroidManifest.xml I use for an app, no external library dependencies though. You could try adding+modifying this to get the deploy to work?
File structure:
/my-project-dir
├── android
│ ├── AndroidManifest.xml
│ └── res
│ └── drawable-mdpi
│ └── icon.png
├── my-project.pro
AndroidManifest.xml:
<?xml version="1.0"?>
<manifest package="my_package_name" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="my_app_name" android:icon="#drawable/icon">
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="my_app_name" android:screenOrientation="unspecified" android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="#array/qt_sources"/>
<meta-data android:name="android.app.repository" android:value="default"/>
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="#array/qt_libs"/>
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="#array/bundled_libs"/>
<!-- Deploy Qt libs as part of package -->
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="#array/bundled_in_lib"/>
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="#array/bundled_in_assets"/>
<!-- Run with local libs -->
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
<meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
<!-- Messages maps -->
<meta-data android:value="#string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
<meta-data android:value="#string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
<meta-data android:value="#string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
<!-- Messages maps -->
<!-- Splash screen -->
<!--
<meta-data android:name="android.app.splash_screen_drawable" android:resource="#drawable/logo"/>
-->
<!-- Splash screen -->
</activity>
</application>
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="14"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
Remove the comment if you do not require these default permissions. -->
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
Remove the comment if you do not require these default features. -->
<!-- %%INSERT_FEATURES -->
<!-- %%INSERT_PERMISSIONS -->
</manifest>
I recently tried packaging a Java app for distribution in the Mac App Store, but discovered that by bundling the default JRE, the app increased its file size by about 138 MB. I would like to reduce the size of the JRE by stripping out components that I don't need (e.g. Corba, JavaFX, XML parsing), thus resulting in a smaller increase when I bundle it into an app.
There are a couple of questions, like this one, that give some guidelines about what components to remove, but none that actually describe how to go about reducing it. What do I need to do to reduce the size of the JRE? Are there certain tools? Do I just download the source and hack out the classes I don't want? Do I edit my currently installed JRE? I'm not really sure where to begin.
I havent tested this myself but after some searching heres what I have found.
The Packaging a Java App for Distribution on a Mac guide gives you a basic look at how to bundle the app (which it sounds like you got already). From there I followed the docs for app bundler, on that page under "runtime" you see you can explicitly include or exclude files/folders from the bundling.
According to their docs
"By default, only the contents of the jre/ directory will be included with the bundled application. All executable content (i.e. bin/, jre/bin/) is excluded. Additional content can be included or excluded using nested <include> and <exclude> elements, respectively."
From that I took their sample code and added an exclude statement:
<-- Import environment variables -->
<property environment="env"/>
<-- Define the appbundler task -->
<taskdef name="bundleapp" classname="com.oracle.appbundler.AppBundlerTask"/>
<-- Create the app bundle -->
<target name="bundle-swingset" depends="package">
<bundleapp outputdirectory="."
name="Test"
displayname="Test"
identifier="com.oracle.javafx.swing.Test"
shortversion="1.0"
applicationCategory="public.app-category.developer-tools"
mainclassname="com/javafx/main/Main">
<runtime dir="${env.JAVA_HOME}">
<exclude name="Java IDL Server Tool" /> <!-- exclude from bundle -->
</runtime>
<classpath file="${user.home}/bin/javafx-samples-2.2.0/SwingInterop.jar"/>
<option value="-Dapple.laf.useScreenMenuBar=true"/>
</bundleapp>
</target>
A full list of optional excludes can be found in the JRE root - $JAVA_HOME/README.txt. Do a find for the text Optional Files and Directories and you'll be at the header of it. I am looking at the JRE7 installation on my computer, the JRE6 readme didnt seem to have anything in it.
I know this isn't working the example you're looking for but I hope it helps you figure it out.
I'm developing an application using PhoneGap in Eclipse and whenever I use the Media object I get an exception on this line:
var test = new Media("/android_asset/www/sound/music/Weird.mp3", null, null, null);
12-31 13:52:56.775: E/Web Console(3688): Uncaught ReferenceError:
Media is not defined:25
This exception is, supposedly, due to the fact that I haven't implemented the Media plugin. I just upgraded from 2.9 to 3.3 so there were some changes with the new plugin-system that I haven't used before.
I tried to follow the instructions in the PhoneGap Media documentation but it kept refering to the use of their Command Line Interface. I'm working in Eclipse and I have created the entire project in eclipse, built the Cordova-3.3.0.jar file myself and then added it to the project. Everything works fine up until the use of the Media object.
Anyone have any idea how to add support for Media to a PhoneGap 3.3.0 project? Can I use the CLI on a project created in Eclipse?
I tried to just add support for it by adding the following to my res/xml/config.xml file:
<feature name="Media">
<param name="android-package" value="org.apache.cordova.AudioHandler" />
</feature>
and then adding the proper permissions in my AndroidManifest file:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
but that didn't work very well either. Any help would be greatly appreciated!
Right. The problem was that I created my Eclipse project using only the Cordova-3.3.0.jar file I had manually built from the source. I should've just created the project using the Command Line Interface as the manual clearly states, added the Media (also through the CLI) and then imported the entire project into Eclipse using File => New => Other => Android from Existing Source.
I got it working now doing it as I described above, hopefully this might help someone some day :P
I'm working on a PhoneGap/Cordova plugin that's supposed to provide a socket for sending and receiving OSC messages (Open Sound Control). For that purpose I'd like to use JavaOSC but I'm uncertain about how to include the library into my project.
I'm using Android Studio and I've basically followed this tutorial to set up my project. First I placed the raw JavaOSC class-files in the same directory as my OSCPlugin.class and placed the import declarations at the to of my OSCPlugin.class:
import com.illposed.osc;
That didn't work.
As a next step I tried to add the library from maven within the project's module settings. I was able to download the jar files from maven and install put them into /platforms/android/libs. Within the settings for the module 'android' I can see that 'Android API 17' is supposed to be used as SDK, including cordova-3.1.0 and com.illposed.osc:javaosc-core:0.2 - both activated. I can see the cordova-3.1.0.jar as well as javaosc-core-0.2.jar, containing com.illposed.osc in the navigator within Android Studio.
However, when trying to compile my project I get:
Gradle: cannot find symbol class osc
triggered from within OSCPlugin.class that contains the above mentioned import declaration
I have very little experience with Java and even less with Android development. But I'd be interested in solving this riddle and get started. I have searched the Java docs but the problem doesn't merely lie within Java but rather within the structure of the Android project.
I'd be thankful if someone could shed some light on this issue. Any hint's highly appreciated!
For one of my Phonegap projects I needed the Apache Commons Net, trying to follow these steps:
...
<source-file src="src/android/xxx.jar" target-dir="libs" framework="true" />
<source-file src="src/android/MyPlugin.java" target-dir="src/com/mypackage" />
...
unfortunately, without success. The trick was to embed the third-party library in another plugin (following the very plugin structure). Having the org.apache.commons.net as a top level directory:
org.apache.commons.net
+src
+android(this is where the .jar is located)
+www (empty, not referencing any .js)
+plugin.xml
For brevity, plugin.xml as follows:
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
id="org.apache.commons.net"
version="0.1.0">
<name>org.apache.commons.net</name>
<description>org.apache.commons.net</description>
<license>Apache License, Version 2.0</license>
<keywords>org.apache.commons.net</keywords>
<!-- android -->
<platform name="android">
<config-file target="res/xml/config.xml" parent="/*">
<feature name="org.apache.commons.net">
<param name="android-package" value="org.apache.commons.net"/>
</feature>
</config-file>
<source-file src="src/android/commons-net-2.2.jar" target-dir="libs" framework="true" />
</platform>
</plugin>
Assuming the org.apache.commons.net directory is located in your local git repo, adding it to your project is as trivial as:
phonegap local plugin add /path/to/your/org.apache.commons.net
To add external library, basically all you have to do is copy the jar to the /libs folder.
Here you have a bad import in your source.
import is used to import a class by specifying the package name followed by the class name and here you only specify the class name, so the error "cannot find symbol class osc" you are having is because there is no class osc.
You should use either
import com.illposed.osc.*; if you want to import all classes from the package
or add an import for each class from the package that you are going to use.
And if you want make the plugin installable using the CLI or phonegap build, you also have to update plugin.xml to add the copy of the jar file.
ps in case you don't know, you won't be able to use classes from com.illposed.osc.ui as they are using swing and designed for the jvm and not android.
I am currently developing an Android app using cordova 2.0. Obviously the plugins.xml has been depreciated and everything is now housed in config.xml. I was just wondering if anyone has managed to get the Phonegap Screenshot plugin working in Eclipse and Cordova 2.0 working on android.
Plugin can be found:
https://github.com/josemando/phonegap-plugins/tree/master/Android/Screenshot
I have added:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
to my Android manifest xml. And made sure that:
<plugin name="Screenshot" value="org.apache.cordova.Screenshot"/>
is added to my config.xml (that now contains all plugin information from plugin.xml)
Screenshot.js is added to the directory:
assets/www/js/
However I am unsure where exactly to place the Screenshot.java file. The example has it in:
src / org / apache / cordova /
However as I did not have this directory I simply placed it in:
src/uk.co..appname1.appname2/
When I did this however it produced errors, the first one being:
The declared package "org.apache.cordova" does not match the expected package "uk.co.mysitename.appname1.appname2" Screenshot.java /Project Name/src/uk/co/mysitename/appname1/appname2line 8 Java Problem
This refers to this line in the Screenshot.js:
package org.apache.cordova;
The two suggested actions to fix this are to:
Move 'Screenshot.java' to package 'org.apache.cordova' (this directory doesn't exsist atm)
Or change package directory to 'uk.co.mysitename.appname1.appname2'
The second error says:
The method run() of type new Runnable(){} must override a superclass method
The suggested action for this being to "remove '#override' annotation"
I have tried to do every possible combination of these however I cannot seem to make progress and get it all to link up. Usually because it thinks that CordovaRef isn't referenced. I am unsure if the plugin even works on Cordova 2.0.0. I have some experience with Phonegap/Cordova but only in ios with Xcode and Objective C plugins. I am new to Java, Eclipse and Android. Any help or clarification on any of these matters would be greatly appreciated.
Answer resolved by:
Phonegap Screenshot plugin in Cordova 2.0.0
Answer/solution provided by Simon MacDonald