It looks as if in recent versions of Android, EncodingUtils from the Apache package has been deprecated. We call EncodingUtils.getBytes(postData, "base64") a lot in our code which now needs to be upgraded. Is there any way we could achieve the end using a more modern way?
If you want to use only EncodingUtils you can add the legacy dependency for Apache
android {
useLibrary 'org.apache.http.legacy'
}
In case your postData is a buffer it is enough to just call
byte[] bytes = {...}
String str = new String(bytes, "UTF-8"); // for UTF-8 encoding`
Related
Background
Suppose I make an Android library called "MySdk", and I publish it on Jitpack/Maven.
The user of the SDK would use it by adding just the dependency of :
implementation 'com.github.my-sdk:MySdk:1.0.1'
What I'd like to get is the "1.0.1" part from it, whether I do it from within the Android library itself (can be useful to send to the SDK-server which version is used), or from the app that uses it (can be useful to report about specific issues, including via Crashlytics).
The problem
I can't find any reflection or gradle task to reach it.
What I've tried
Searching about it, if I indeed work on the Android library (that is used as a dependency), all I've found is that I can manage the version myself, via code.
Some said I could use BuildConfig of the package name of the library, but then it means that if I forget to update the code a moment before I publish the dependency, it will use the wrong value. Example of using this method:
plugins {
...
}
final def sdkVersion = "1.0.22"
android {
...
buildTypes {
release {
...
buildConfigField "String", "SDK_VERSION", "\"" + sdkVersion + "\""
}
debug {
buildConfigField "String", "SDK_VERSION", "\"" + sdkVersion + "-unreleased\""
}
}
Usage is just checking the value of BuildConfig.SDK_VERSION (after building).
Another possible solution is perhaps from gradle task inside the Android-library, that would be forced to be launched whenever you build the app that uses this library. However, I've failed to find how do it (found something here)
The question
Is it possible to query the dependency version from within the Android library of the dependency (and from the app that uses it, of course), so that I could use it during runtime?
Something automatic, that won't require me to update it before publishing ?
Maybe using Gradle task that is defined in the library, and forced to be used when building the app that uses the library?
You can use a Gradle task to capture the version of the library as presented in the build.gradle dependencies and store the version information in BuildConfig.java for each build type.
The task below captures the version of the "appcompat" dependency as an example.
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.0'
}
task CaptureLibraryVersion {
def libDef = project.configurations.getByName('implementation').allDependencies.matching {
it.group.equals("androidx.appcompat") && it.name.equals("appcompat")
}
if (libDef.size() > 0) {
android.buildTypes.each {
it.buildConfigField 'String', 'LIB_VERSION', "\"${libDef[0].version}\""
}
}
}
For my example, the "appcompat" version was 1.4.0. After the task is run, BuildConfig.java contains
// Field from build type: debug
public static final String LIB_VERSION = "1.4.0";
You can reference this field in code with BuildConfig.LIB_VERSION. The task can be automatically run during each build cycle.
The simple answer to your question is 'yes' - you can do it. But if you want a simple solution to do it so the answer transforms to 'no' - there is no simple solution.
The libraries are in the classpath of your package, thus the only way to access their info at the runtime would be to record needed information during the compilation time and expose it to your application at the runtime.
There are two major 'correct' ways and you kinda have described them in your question but I will elaborate a bit.
The most correct way and relatively easy way is to expose all those variables as BuildConfig or String res values via gradle pretty much as described here. You can try to generify the approach for this using local-prefs(or helper gradle file) to store versions and use them everywhere it is needed. More info here, here, and here
The second correct, but much more complicated way is to write a gradle plugin or at least some set of tasks for collecting needed values during compile-time and providing an interface(usually via your app assets or res) for your app to access them during runtime. A pretty similar thing is already implemented for google libraries in Google Play services Plugins so it would be a good place to start.
All the other possible implementations are variations of the described two or their combination.
You can create buildSrc folder and manage dependencies in there.
after that, you can import & use Versions class in anywhere of your app.
I am having com.squareup.okhttp3:okhttp-urlconnection:3.13.1 jar as dependency in gradle file of my Android project and used as below to get the URLConnection.
protected URLConnection getStandardHTTPURLConnection(URL url) throws IOException {
return new OkHttpURLConnection(url, builder.cookieJar(new JavaNetCookieJar(CookieHandler.getDefault())).build());
}
So I updated the jar to 4.9.0 and realized that OkHttpURLConnection is not available. It is leading to noClassDefinition exception in the run time. so what are the alternatives? Is it deprecated or moved under another hood?
Below are my imports.
import okhttp3.internal.huc.OkHttpURLConnection;
import okhttp3.internal.huc.OkHttpsURLConnection;
Kindly advice.
There's a compatibility implementation you can paste in that's mentioned in the OkHttp 3.14.0 release notes.
https://square.github.io/okhttp/changelog_3x/#version-3140
From https://square.github.io/okhttp/changelog_3x/ so I guess they got removed on 4.x
The Apache HTTP client and HttpURLConnection APIs are deprecated. They
continue to work as they always have, but we’re moving everything to
the new OkHttp 3 API. The okhttp-apache and okhttp-urlconnection
modules should be only be used to accelerate a transition to OkHttp’s
request/response API. These deprecated modules will be dropped in an
upcoming OkHttp 3.x release.
I'm trying to migrate some Java library from 'normal' JVM to android and stuck with some Java11 APIs used in the code.
The first thing I already got - Java11 language features seems to work only with Canary build of Android Studio, see answer here
Now I need to get understanding about which APIs can be really used. Here are two use-cases which do not work for me and I can't get if I'm doing something wrong or it never should work:
List.copyOf() - introduced in Java11, method copyOf is not available on android. Methods 'List.of()', introduced with Java 9, work OK.
class java.lang.invoke.LambdaMetafactory - introduced with Java 1.8 - to be used for programmatic creation of lambdas for usage instead for reflection, is not visible on Android.
I see both of them in sources of desugar_jdk_libs here:
https://github.com/google/desugar_jdk_libs/blob/master/jdk11/src/java.base/share/classes/java/lang/invoke/LambdaMetafactory.java
https://github.com/google/desugar_jdk_libs/blob/master/src/share/classes/java/util/List.java
So - the question is: how can I identify if some Java API is supposed to be available in 'desugared' android build or no? What really can be expected from 'desugaring'?
Steps to reproduce:
Using Android Studio Canary generate a dummy "Basic Activity" project
Make sure following is provided in build.gradle
android {
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
}
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
}
Add following lines somewhere in code
List<Integer> ints1 = List.of(1, 2, 3);
Supplier<List<Object>> listSupplier = () -> new ArrayList<>();
List<Object> alist = listSupplier.get();
List<Integer> ints2 = List.copyOf(ints1);
LambdaMetafactory.metafactory(null,null,null,null,null,null);
Last 2 lines fail to compile for me.
PS: final application is supposed to work on Android 10+.
Contrary to the other answer, desugaring is totally possible.
The dependency to add is
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
}
You can find more information at the official Android Java 8 desugaring documentation.
Desugaring lib is considered unofficial. We can't expect an exact answer. We get the feature when it is ready. Now List.copyOf() method now working with the latest Gradle version.
About the LambdaMetafactory class, It is not included in Android Javadoc. This means we assume we don't have LambdaMetafactory at all. Google stripped down some java API for being lightweight.
In general, We should check android Javadoc first. If android Javadoc has no mention about some API. We can be sure we won't get that feature anytime soon.
client.post(AppConfig.getApplicationContext(),
HttpUrls.getUrl()
+ urlroot, new StringEntity(jsonData, "UTF-8"),
"application/json", handler);
I use StringEntity as HttpEntity when I post a request by XHttpClient in Android API 21, but when I use Android API 23, I cannot use it again. I think there should be a class in API 23 which equivalent to the class StringEntity in API 21, so which class can I use?
Support for Apache HTTP Client has been removed from Android 6.0. Check Android 6.0 changes.
Android 6.0 release removes support for the Apache HTTP client. If your app is using this client and targets Android 2.3 (API level 9) or higher, use the HttpURLConnection class instead. This API is more efficient because it reduces network use through transparent compression and response caching, and minimizes power consumption. To continue using the Apache HTTP APIs, you must first declare the following compile-time dependency in your build.gradle file:
android {
useLibrary 'org.apache.http.legacy'
}
We know that Android M has removed support for HttpClient. Apps linking with it will have to explicitly say so: add a library dependency in your gradle file.
But does it break backward compatibility with existing applications?
Suppose I wrote an app which supports Api level 1 and higher and it's never maintained since last year. The targetSdkLevel of the app is certainly lower than 22. Will it crash on Android M? The source code could have been lost.
The answer looks to be yes.
I looked in the Android M source code through the SDK manager, and the package for the client is not in the source.
Package name for the HttpClient:
org.apache.http.client.HttpClient
Existing paths:
org.apache.http.conn
org.apache.http.params
Ways to fix this:
Add this to your build.graddle:
android {
useLibrary 'org.apache.http.legacy'
}
Use OkHttp-UrlConnection as an almost drop in replacement by adding this to your build.graddle:
compile 'com.squareup.okhttp:okhttp-urlconnection:2.4.0'
Example usage:
private static OkHttpClient okHttpClient = new OkHttpClient();
HttpURLConnection urlConnection = new OkUrlFactory(okHttpClient).open(url);