PoC of Java8 Standard Library for Android for API version >= 15
OTHER License
"Java8 support" in Android is sometimes misunderstood because it includes a few independent issues.
Java8 Language Feature is usually syntactic one, for example lambda expressions or default methods; in Android, this is solved by tools like retrolambda
or desugar
.
Java8 API, or Standard Library, is runtime library on the platform. The support of Standard Library in Android is more difficult than Language Feature, because dex, Dalvik executable file format, does not allow bundle Standard Library in APK. In fact, it was considered impossible -- before this project shows its possibility.
Retropiler deals with the latter: it makes dex to bundle Java8 standard library by replacing its references to the original ones.
For example, the following code works on devices with Android API level 15 after processing by retropiler:
import java.util.Optional;
Optional<String> optStr = Optional.of("foo");
assertThat(optStr.get(), is("foo")); // it works!
Here is the magic.
The basic idea is that replacing Java8-specifc classes / methods to the bundled version of them with bytecode weaving.
That is, the above code is transformed into:
import io.github.retropiler.runtime.java.util._Optional;
_Optional<String> optStr = _Optional.of("foo");
assertThat(optStr.get(), is("foo")); // it works!
It can work even on Android API 15.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'io.github.retropiler:retropiler-gradle-plugin:0.0.5'
}
}
apply plugin: 'io.github.retropiler'
Iterable#forEach()
Arrays.asList("foo", "bar").forEach(item -> {
Log.d("XXX", item);
});
java.util.Optional
Optional<String> optStr = Optional.of("baz");
optStr.ifPresent(str -> {
Log.d("XXX", str);
});
java.util.function
packageNot all the functions are tested yet.
You can customize mapping of stndard class to alternative runtime class:
apply plugin: 'io.github.retropiler'
retropiler {
// the default runtime package
runtimePackage "io.github.retropiler.runtime"
// the default mapping function
mapClassName { ext, ctClass ->
// e.g. map java.util.Optional to io.github.retropiler.runtime.java.util._Optional
"${ext.runtimePackage}.${ctClass.packageName}._${ctClass.simpleName}"
}
}
Retropiler depends on Retrolambda to transform lambda expressions to anonymous classes.
The methods defined in runtime/
are here:
io.github.retropiler:retropiler-runtime:0.0.5
retrolambda
There are three modules to publish:
plugin/
- Gradle pluginruntime/
- runtime libraryannotations/
- annotation libraryYou can publish them by:
make publish
with properties in ~/.gradle/gradle.properties
:
bintrayUser=$user
bintrayKey=$key
FUJI Goro (gfx).
And contributors are listed here: Contributors
The class library in runtime module comes from Open JDK via AOSP.
The Java source files in runtime/
module which were copied from AOSP, are licensed under GPL v2+CE as described in each file.
Other modules except for runtime/
are licensed under Apache License 2.0:
Copyright (c) 2017 The Retropiler Project.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.