Skip to content

Latest commit

 

History

History
471 lines (351 loc) · 18.8 KB

FAQ.md

File metadata and controls

471 lines (351 loc) · 18.8 KB

FAQ

(for contributors, see CONTRIBUTING.md)

Table of Contents

Start here for debugging (aka it's not working; aka don't panic)

Some common misconfigurations can cause numerous Gradle errors.

  1. First make sure you have a supported version of j2objc and Xcode (see README.md for our current supported versions) installed locally, and that your J2OBJC_HOME property is set correctly to the distribution directory of j2objc. This is not the source repository root for j2objc. The distribution directory should have at minimum lib/ and include/ subdirectories. (If you download j2objc release .zip files from https://github.com/google/j2objc, you get only the distribution by default.)

  2. Verify you are using the latest released version of the plugin. Forks of the plugin exist; if you are looking for help at https://github.com/j2objc-contrib/j2objc-contrib (the original), please use the latest version distributed from https://plugins.gradle.org/plugin/com.github.j2objccontrib.j2objcgradle.

  3. If you are still getting errors regarding classes, executables, Jars, or libraries that cannot be found, and you've verified that your J2OBJC_HOME is set correctly, you may have stale Gradle caches, which can be cleared as follows. Note the following steps will cause you to rebuild everything, so the next build may take a long time.

# (from your Gradle project's root directory)
# Stops any Gradle daemons if they are running.
./gradlew --stop
# Remove cached Gradle database.
rm -rf .gradle/
# Remove cached Gradle outputs.
rm -rf build/

Now try building again.

How do I develop with Xcode?

When using the j2objcTask, open the .xcworkspace file in Xcode. If the .xcodeproj file is opened in Xcode then CocoaPods will fail. This will appear as an Xcode build time error:

library not found for -lPods-IOS-APP-j2objc-shared

Also see the FAQ note on developing with Swift.

How can I speed up my build?

You can reduce the build time by 50% by skipping the release binaries by adding the following to your root level local.properties file:

j2objc.release.enabled=false

This is helpful for a tight modify-compile-test loop using only debug binaries. You can also do this for j2objc.debug.enabled.

If you'd rather just disable release builds for a particular run of the command line:

J2OBJC_RELEASE_ENABLED=false ./gradlew build

The local.properties value overrides the environment variable, if present.

What libraries are linked by default?

A number of standard libraries are included with the J2ObjC releases and linked by default when using the plugin. To add other libraries, see the FAQs about dependencies. The standard libraries are:

com.google.guava:guava
com.google.j2objc:j2objc-annotations
com.google.protobuf:protobuf-java
junit:junit (test only)
org.mockito:mockito-core (test only)
org.hamcrest:hamcrest-core (test only)

What should I add to .gitignore?

The .gitignore file should follow existing conventions for Android Studio and Xcode. Once that's configured, check it contains the following:

# Includes j2objc.home setting (Android Studio should have added this)
local.properties

# CocoaPods temporary files used for Xcode
Pods/

What is the recommended folder structure for my app?

This is the suggested folder structure. It also shows a number of generated files and folders that aren't committed to your repository (marked with .gitignore). Files are shown before folders, so it is not in strict alphabetical order.

workspace
├── .gitignore                     // Add Ignores: local.properties, build/, Pod/
├── build.gradle
├── local.properties               // sdk.dir=<Android SDK> and j2objc.home=<J2ObjC>, .gitignore
├── settings.gradle                // include ':android', ':shared'
├── android
│   ├── build.gradle               // dependencies { compile project(':shared') }
│   └── src/...                    // src/main/java/... and more, only Android specific code
├── ios
│   ├── IOS-APP.xcodeproj          // Xcode project, which is modified by j2objcXcode / CocoaPods
│   ├── Podfile                    // j2objcXcode modifies this file for use by CocoaPods, committed
│   ├── WORKSPACE.xcworkspace      // Xcode workspace
│   ├── IOS-APP/...                // Xcode workspace
│   ├── IOS-APPTests/...           // j2objcXcode configures as above but with "debug" buildType
│   └── Pods/...                   // temp files generated by CocoaPods for Xcode, .gitignore
└── shared
    ├── build.gradle               // apply 'java' then 'j2objc' plugins
    ├── build                      // generated build directory, .gitignore
    │   ├── ...                    // other build output
    │   ├── binaries/...           // Contains test binary: testJ2objcExecutable/debug/testJ2objc
    │   ├── j2objc-shared.podspec  // j2objcXcode generates these settings to modify Xcode
    │   └── j2objcOutputs/...      // j2objcAssemble copies libraries and headers here
    ├── lib                        // library dependencies, must have source code for translation
    │   ├── lib-with-src.jar       // library with source can be translated, see FAQ on how to use
    │   └── libpreBuilt.a          // library prebuilt for ios, see FAQ on how to use
    └── src/...                    // src/main/java/... shared code for translation

What tasks does the plugin add to my project?

These are the main tasks for the plugin:

j2objcCycleFinder - Find memory cycles that can cause leaks, see FAQ for more details
j2objcTranslate   - Translates Java source to Objective-C
j2objcAssemble    - Outputs packed libraries, source & resources to build/j2objcOutputs
j2objcTest        - Runs all JUnit tests in the translated code
j2objcBuild       - Runs j2objcAssemble and j2objcTest, doesn't run j2objcXcode
j2objcXcode       - Xcode updated with libraries, headers & resources (uses CocoaPods)

Running the build task from the Gradle Java plugin will automatically run the j2objcBuild command and all the previous tasks (which it depends on). Only the j2objcXcode task needs to be manually run. Note that you can use the Gradle shorthand of $ gradlew jA to do the j2objcAssemble task. The other shorthand expressions are jCF, jTr, jA, jTe, jB and jX.

What version of Gradle do I need?

You need at least Gradle version 2.4, due to support for native compilation features.

How do I solve the Eclipse error message Obtaining Gradle model...?

You have to first create the Gradle wrapper. Go to your project folder and do gradle wrapper. Refresh your Eclipse project.

How do I properly pass multiple arguments to J2ObjC?

Make sure your arguments are separate strings, not a single space-concatenated string.

j2objcConfig {
    // CORRECT
    translateArgs '-use-arc'
    translateArgs '-prefixes', 'file.prefixes'

    // CORRECT
    translateArgs '-use-arc', '-prefixes', 'file.prefixes'

    // WRONG
    translateArgs '-use-arc -prefixes file.prefixes'
}

Why is my clean build failing?

This is a known issue if you don't have any tests. If you are doing ./gradlew clean build, try instead ./gradlew clean && ./gradlew build.

When you don't have any test source files, the plugin creates a placeholder to force the creation of a test binary; this is done during project configuration phase, but clean deletes this file before build can use it.

How do I include Java files from additional source directories?

In order to include source files from sources different than src/main/java you have to modify the Java plugin's sourceSet(s). For example, if you want to include files from src-gen/base both into your JAR and (translated) into your Objective C libraries, then add to your shared/build.gradle:

sourceSets {
    main {
        java {
            srcDir 'src-gen/base'
        }
    }
}

How do I develop with Swift?

To work with Swift in Xcode, you need to configure a bridging header. Within that bridging header, include the files needed for using the JRE and any classes that you'd like to access from Swift code. Also see the FAQ item on file not found errors.

// File: ios/IOS-APP/IOS-APP-bridging-header.h

// J2ObjC requirement for Java Runtime Environment
// Included from /J2OBJC_HOME/include
#import "JreEmulation.h"

// Swift accessible J2ObjC translated classes
// Included from `shared/build/j2objcOutputs/src/main/objc`
#import "MyClassOne.h"
#import "MyClassTwo.h"

How do I solve 'File not found' import error in Xcode?

This is typically caused by a limitation of Xcode that expects all the source to be in a top-level directory. You need to use the --no-package-directories argument to flatten the hierarchy. The plugin will warn if two files are mapped to a conflicting name.

j2objcConfig {
    translateArgs '--no-package-directories'
    ...
}

Example error:

Bridging-Header.h:6:9: note: in file included from Bridging-Header.h:6:
#import "MyClass.h"
        ^
Template.h:10:10: error: 'com/test/AnotherClass.h' file not found
#include "com/test/AnotherClass.h"

How do I work with Package Prefixes?

For the class com.example.dir.MyClass, J2ObjC will by default translate the name to ComExampleDirMyClass, which is a long name to use. With package prefixes, you can shorten it to something much more manageable, like CedMyClass. See the example below on how to do this. Also see the reference docs on package name prefixes.

// File: build.gradle
j2objcConfig {
    translateArgs '--prefixes', 'resources/prefixes.properties'
    ...
}
// File: resources/prefixes.properties
// Storing at this location allows Class.forName(javaName) to work for mapped class.
com.example.dir: Ced
com.example.dir.subdir: Ceds

As of J2ObjC verion 0.9.8 you can also use wildcards in your prefixes file. This will map packages such as com.example.dirandcom.example.dir.subdir both to Ceds.

com.example.dir.*: Ceds

How do I enable ARC for my Objective-C classes?

Add the following to your configuration block. See.

j2objcConfig {
   translateArgs '-use-arc'
   extraObjcCompilerArgs '-fobjc-arc'
}

How do I call finalConfigure()?

You must always call finalConfigure() at the end of j2objcConfig {...} within your project's build.gradle file. You need to include an otherwise empty j2objcConfig {...} block with this call even if you do not need to customize any other j2objConfig option.

j2objcConfig {
    ...
    finalConfigure()
}

Why is my Android build so much slower after adding j2objc?

Depending on your Android Studio 'run configuration', you may be building more of your Gradle project than is neccessary. For example if your run configuration includes a general 'Make' task before running, it will build all your gradle projects, including the j2objc parts. Instead make sure your run configuration only performs the :android:assembleDebug task:

Run Configuration

At the command line, if you want to use the debug version of your Android app, make sure you are running ./gradlew :android:assembleDebug and not for example ./gradlew build.

Error: implicit declaration of function 'JreRelease' is invalid in C99 [-Werror,-Wimplicit-function-declaration] JreRelease(this$0_)

See: How do I enable ARC for my Objective-C classes?

How do I disable a plugin task?

You can disable tasks performed by the plugin using the following configuration block in your build.gradle. This is separate and alongside the j2objcConfig settings. For example, to disable the j2objcTest task, do the following:

// File: shared/build.gradle
j2objcTest {
    enabled = false
}
j2objcConfig {
    ...
}

How do I setup dependencies with J2ObjC?

See dependencies.md.

Cycle Finder Basic Setup

This task is disabled by default as it requires greater sophistication to use. It runs the cycle_finder tool in the J2ObjC release to detect memory cycles in your application. Objects that are part of a memory cycle on iOS won't be deleted as it doesn't support garbage collection.

The basic setup will implicitly check for 40 memory cycles - this is the expected number of erroneous matches with jre_emul library for J2ObjC version 0.9.6.1. This may cause issues if this number changes with future versions of J2ObjC libraries.

// File: shared/build.gradle
j2objcCycleFinder {
    enabled = true
}

Also see FAQ's Advanced Cycle Finder Setup.

Cycle Finder Advanced Setup

This uses a specially annotated version of the jre_emul source that marks all the erroneously matched cycles such that they can be ignored. It requires downloading and building the J2ObjC source:

  1. Download the J2ObjC source to a directory (hereafter J2OJBC_REPO):

    https://github.com/google/j2objc

  2. Within the J2OJBC_REPO, run:

    (cd jre_emul && make java_sources_manifest)

  3. Configure j2objcConfig in shared/build.gradle so CycleFinder uses the annotated J2ObjC source and whitelist. Note how this specifies an expected cycle count of zero, as the JRE cycles are already accounted for in the generated whitelist. If however, you have additional cycles you expect, you should use that number instead of zero.

// File: shared/build.gradle
j2objcConfig {
    cycleFinderArgs '--whitelist', 'J2OBJC_REPO/jre_emul/cycle_whitelist.txt'
    cycleFinderArgs '--sourcefilelist', 'J2OBJC_REPO/jre_emul/build_result/java_sources.mf'
    cycleFinderExpectedCycles 0
}

For more details:

How do I develop on Windows or Linux?

Windows and Linux support is limited to the j2objcCycleFinder and j2objcTranslate tasks. Mac OS X is required for the j2objcAssemble, j2objcTest and j2objcXcode tasks (see task descriptions) This matches the J2ObjC Requirements.

It is recommended that Windows and Linux users use translateOnlyMode to reduce the chances of breaking the iOS / OS X build. This can be done by those developers configuring their local.properties (the Mac OS X developers should not use this):

# File: local.properties
j2objc.translateOnlyMode=true

How do I fix missing required architecture linker warning?

If you see a message similar to:

ld: warning: ignoring file /PATH/j2objcOutputs/lib/iosDebug/libPROJECT-j2objc.a,
missing required architecture i386 in file /PATH/j2objcOutputs/lib/iosDebug/libPROJECT-j2objc.a
(3 slices)

and additionally get linker errors, you are not building all the neccessary architectures.

By default (for performance), we build only modern iOS device and simulator architectures. If you need i386 for older simulators (iPhone 5, 5c and earlier devices), add the following to your build.gradle file:

// File: build.gradle
j2objcConfig {
    supportedArchs += ['ios_i386']
}