Apache Commons Codec with Android: could not find method - android

Today I tried including the apache.commons.codec package in my Android application and couldn't get it running. Android could not find method ord.apache.commons.codec.binary.* and output the following errors in DDMS
01-12 08:41:48.161: ERROR/dalvikvm(457): Could not find method org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString, referenced from method com.dqminh.app.util.Util.sendRequest
01-12 08:41:48.161: WARN/dalvikvm(457): VFY: unable to resolve static method 10146: Lorg/apache/commons/codec/binary/Base64;.encodeBase64URLSafeString ([B)Ljava/lang/String;
01-12 08:41:48.161: WARN/dalvikvm(457): VFY: rejecting opcode 0x71 at 0x0004
Any clue on how to solve this problem ? Thanks a lot.

I had a similar problem while using android with an OAuth library I'm developing.
I also got from android that, although I had included apache.commons.codec in the classpath, a particular method (encodeBase64String) was not found.
Checking the javadocs, both methods claim to be 1.4 and greater only, so my guess is that android already includes an older version of commons.codec where these methods are indeed undefined.
My solution was to use an older method, like this:
String encodedString = new String(Base64.encodeBase64('string to encode'));
The method you want to use is different since it replaces + and / with url-safe values - and _. So you probably might use something like:
String encodedString = new String(Base64.encodeBase64('string to encode'));
String safeString = encodedString.replace('+','-').replace('/','_');

You don't have to use apache commons, on android you can use android.util.Base64 instead.

I experienced the exact same problem. So i started browsing the android source code, and as it turns out Pablo Fernandez's guess about Android having an implementation of org.apache.commons.code.binary is correct. However, its version 1.2 of the apache commons, not version 1.4 or even 1.5.
You can see for your self in the android source.
as a note this is question is a duplicate of this post

You can use the following function:
private static String encodeBase64URLSafeString(byte[] binaryData) {
return android.util.Base64.encodeToString(binaryData, Base64.URL_SAFE);
}
source + listing of other possible flags: http://developer.android.com/reference/android/util/Base64.html

My solution to the same problem was to rename the problematic class org.apache.commons.codec.binary.Base64.java into org.apache.commons.codec.binary.ApacheBase64.java. I did it using Eclipse refactor-rename.
That way, the latest and greatest apache solution is preserved and used, and there is no chance for accidental problem recurrence when my app is eventually being lifted from android 1.6 lowest denominator.
Note I had the entire apache commons source tree already set as separate Eclipse java project, next to my Android project. My Android project used many of Apache Commons classes, but failed on Base64 because of above described problems...

You could simply copy this code bit from the apache library (it is pretty isolated)
http://www.java2s.com/Open-Source/Android/Blog-Twitter/twitspeak/org/apache/commons/codec/binary/Base64.java.htm
Edit:
Updated link from the Wayback Machine as the original is gone:
http://web.archive.org/web/20130610025148/http://www.java2s.com/Open-Source/Android/Blog-Twitter/twitspeak/org/apache/commons/codec/binary/Base64.java.htm

Please note that this answer was made by Dylan Watson in the comments above:
Be aware that you need to use Base64.encode("foobar".getBytes(),
Base64.Base64.NO_WRAP); to get exactly the same result as the apache
commons library. See: stackoverflow.com/questions/17912119
This answer was the only which worked after hours of trying to communicate my android app with a java "desktop" app.
So here is some source code, maybe it will help others:
Code from the desktop applet:
private static String convertToBase64(String s) {
byte[] bytes = new byte[0];
try {
bytes = (s.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
return DatatypeConverter.printBase64Binary(bytes);
}
This snippet is used in the android app:
public static String convertToBase64(String password) {
byte[] bPwd = new byte[0];
try {
bPwd = (password.getBytes("UTF-8"));
} catch (Exception e) {
e.printStackTrace();
}
try {
password = new String(Base64.encode(bPwd, Base64.NO_WRAP), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return password;
}

You can simply import the following library under Gradle dependency
dependencies {
implementation "commons-codec:commons-codec:1.11"
}
It will work

did you include apache commons project lib,like
org.apache.commons:commons-compress
org.apache.commons:commons-email
org.apache.commons:commons-io
org.apache.commons:commons-lang3
org.apache.commons:commons-parent
org.apache.commons:commons-pool2
the commons-codec 's GAV is
commons-codec:commons-codec
but it's package name is
org.apache.commons.codec
this package name will be conflict with apache commons project libs,try to change the package name of commons-codec,then generate it as a jar or import the source code had changed the package name;

Knowing that this is an old question, but I faced this problem recently when compiling for API Level 23, and found another solution for the problem: use guava project.
// Encoding
String encodedString = BaseEncoding.base64().encode(text.getBytes(UTF_8));
System.out.println("encodedString: " + encodedString);
// Decoding
byte[] decodedString = BaseEncoding.base64().decode(encodedString);
System.out.println("decodedString: " + new String(decodedString, UTF_8));
The guava library (18.0) was the version that I've used, and the change was smooth. The code works as expected.
Solution found in here: https://memorynotfound.com/encode-decode-base64-string-using-native-java/

This works for me:
import org.apache.commons.codec.binary.Base64;
/**
* This is used to get the base64 from the bytes
*
* #param rawBytes the raw bytes
* #return the base64 encoded string
*/
public static String getBase64String(byte[] rawBytes) {
String base64Str = "";
if (rawBytes!= null) {
base64Str= new String(Base64.encodeBase64(rawBytes));
}
return base64Str;
}
public static byte[] getBase64DecodedString(String base64EncodedStr) {
byte[] base64Bytes = Base64.decodeBase64(base64EncodedStr.getBytes());
return bitmap;
}

Related

YouTube API Exception In Initializer Error

So I have been using the YouTube API successfully for the past few months in Android Studio. I went to update my app and as of today the app keeps crashing when it is trying to initialize the YouTube builder. Has anyone else experienced this problem?
mYoutubeDataApi = new YouTube.Builder(mTransport, mJsonFactory, null)
.setApplicationName(getResources().getString(R.string.app_name))
.build();
The app crashes with the following output:
2019-12-09 01:38:06.443 17937-17937/ E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.ExceptionInInitializerError
at com.google.api.services.youtube.YouTube.<clinit>(YouTube.java:44)
at com.google.api.services.youtube.YouTube$Builder.build(YouTube.java:16644)
Line 44 in the YouTube.java file is:
public class YouTube extends com.google.api.client.googleapis.services.json.AbstractGoogleJsonClient {
// Note: Leave this static initializer at the top of the file.
static {
com.google.api.client.util.Preconditions.checkState(
com.google.api.client.googleapis.GoogleUtils.MAJOR_VERSION == 1 &&
com.google.api.client.googleapis.GoogleUtils.MINOR_VERSION >= 15,
"You are currently running with version %s of google-api-client. " +
"You need at least version 1.15 of google-api-client to run version " +
"1.30.1 of the YouTube Data API library.", com.google.api.client.googleapis.GoogleUtils.VERSION);
}
In 1.30.6, they added this: https://github.com/googleapis/google-api-java-client/pull/1419
To fix, edit your build.gradle back down to 1.30.5
dependencies {
implementation ('com.google.api-client:google-api-client:1.30.5')
implementation ('com.google.api-client:google-api-client-android:1.30.5')
}
If there's a better solution, I'd like to hear it!
To further explain why that change in 1.30.6 causes the crash, here's some more info.
Specifically, the issue is coming from this file: https://github.com/googleapis/google-api-java-client/blob/master/google-api-client/src/main/java/com/google/api/client/googleapis/GoogleUtils.java
Caused by: java.lang.IllegalStateException: No successful match so far
at java.util.regex.Matcher.ensureMatch(Matcher.java:1116)
at java.util.regex.Matcher.group(Matcher.java:382)
at com.google.api.client.googleapis.GoogleUtils.<clinit>(Unknown Source:26)
Here is the relevant code
public static final String VERSION = getVersion();
static final Pattern VERSION_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)(-SNAPSHOT)?");
static {
Matcher versionMatcher = VERSION_PATTERN.matcher(VERSION);
versionMatcher.find();
MAJOR_VERSION = Integer.parseInt(versionMatcher.group(1));
MINOR_VERSION = Integer.parseInt(versionMatcher.group(2));
BUGFIX_VERSION = Integer.parseInt(versionMatcher.group(3));
}
private static String getVersion() {
String version = GoogleUtils.class.getPackage().getImplementationVersion();
// in a non-packaged environment (local), there's no implementation version to read
if (version == null) {
// fall back to reading from a properties file - note this value is expected to be cached
try (InputStream inputStream =
GoogleUtils.class.getResourceAsStream("google-api-client.properties")) {
if (inputStream != null) {
Properties properties = new Properties();
properties.load(inputStream);
version = properties.getProperty("google-api-client.version");
}
} catch (IOException e) {
// ignore
}
}
return version;
}
Presumably, getVersion is returning null, although I can't say why. Seeing as how this recently happened for me 2-3 days ago also, something we updated must be conflicting.
This bug is fixed in com.google.api-client:google-api-client:1.30.7. Upgrading to that version or later will fix it.
In the latest version, they have added the library proguard file, which keeps the the GoogleUtils.java and hence keeps the google-api-client.properties which gets generated in build time.
Initially they used to update the string literal for version name for each release hence that time parsing of version name done in GoogleUtils.java was crash free.
But later on they shifted to parsing the version from google-api-client.properties at GoogleUtils.java which started giving error as proguard started removing the generated google-api-client.properties file.
Later on after release, 1.30.9 at this commit id the started using the embedded proguard rule to keep the GoogleUtils.java file
They actually fixed the issue at release, 1.30.8 at the commit, 1.30.9 release just does the same fix in more android recommended way.
Although the final adopted version uses GoogleUtils.class.getResourceAsStream("google-api-client.properties") which is Java api and returns the InputStream to read the google-api-client.properties file. Since these stream may not work perfectly in some devices they still crash but with lesser frequency(as we still see the crashes with the fixed present in the release 1.30.9).
Created an issue to track this

Xamarin SqlServer cant get a connection

I'm building an app with the Entity Framework on Xamarin that lets me compare some data. But when I start my "fetchdata" function, I receive the Error:
System.Data.SqlClient.SqlException (0x80131904): Snix_Connect (provider: SNI_PN7, error: 35 - SNI_ERROR_35)Snix_Connect (provider: SNI_PN7, error: 35 - SNI_ERROR_35)
I see many posts about Xamarin / Android & that it is not possible to get a connection to a SQL Server. Is there any way to fetch data from a SQL Server with .NET Core on Xamarin?
This is the string I put into SQL_Class folder with Sql_Common.cs
Fill up the brace brackets with actual parameters (removing the brace brakets too).
public static string SQL_connection_string = #"data source={server_address};initial catalog={database_name};user id={user_id};password={password};Connect Timeout={seconds}";
Then I access whenever I need it from any xamarin code just like we use in our asp.net c#
This works for me on my app without any issues.
using (SqlConnection Sql_Connection = new SqlConnection(Sql_Common.saralEHR_connection_string))
But as #Jason mentioned in his first reply, I too would get once again check the security part. I fexperienced before publishing Package to Google Play, they encrypt the App files with Hash Key Code and then only it gets upload to server
Yes it is possible (HuurrAYY!):
Im new in .net core, c# and so on and for me it was a hell of a work to get it working..
So here for the other noobs who are seeking for Help:
Guide´s i used:
Building Android Apps with Entity Framework
https://medium.com/#yostane/data-persistence-in-xamarin-using-entity-framework-core-e3a58bdee9d1
https://blog.xamarin.com/building-android-apps-entity-framework/
Scaffolding
https://cmatskas.com/scaffolding-dbcontext-and-models-with-entityframework-core-2-0-and-the-cli/
How i did it:
Build your normal Xamarin app.
create new .net solution like in the tutorials (DONT WRITE YOUR Entity Framework CLASSES)
create a third solution what has to be a .net core console application
Scaffold your DB in your CONSOLE application move all created classes & folders in your "xamarin .net" solution & change the namespaces
Ready to Go!
Side Node: NuGets you need in every solution:
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
[EDIT: NuGets you need in every solution]
I am doing this way (working snippet):
string connectionString = #"data source={server};initial catalog={database};user id={user};password={password};Connect Timeout=10";
string databaseTable = "{table name}";
string selectQuery = String.Format("SELECT count(*) as Orders FROM {0}", databaseTable);
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
//open connection
connection.Open();
SqlCommand command = new SqlCommand(selectQuery, connection);
command.Connection = connection;
command.CommandText = selectQuery;
var result = command.ExecuteScalar().ToString();
//check if there is result
if(result != null)
{
OrdersLabel.Text = result;
}
}
}
catch (Exception ex)
{
OrdersLabel.Text = ex.Message;
}
It is working fine, but API call more elegant.
I hope it helps.

Titanium Hyperloop access to android.os.SystemProperties

I have been trying a ( i hope) simple bit of Android hyperloop code directly within a titanium project (using SDK 7.0.1.GA and hyperloop 3).
var sysProp = require('android.os.SystemProperties');
var serialNumber = sysProp.get("sys.serialnumber", "none");
But when the app is run it reports
Requested module not found:android.os.SystemProperties
I think this maybe due to the fact that when compiling the app (using the cli) it reports
hyperloop:generateSources: Skipping Hyperloop wrapper generation, no usage found ...
I have similar code in a jar and if I use this then it does work, so I am wondering why the hyperloop generation is not being triggered, as I assume that is the issue.
Sorry should have explained better.
This is the jar source that I use, the extraction of the serial number was just an example (I need access to other info manufacturer specific data as well), I wanted to see if I could replicate the JAR functionality using just hyperloop rather that including the JAR file. Guess if it's not broke don't fix it, but was curious to see if it could be done.
So with the feedback from #miga and a bit of trial and error, I have come up with a solution that works really well and will do the method reflection that is required. My new Hyperloop function is
function getData(data){
var result = false;
var Class = require("java.lang.Class");
var String = require("java.lang.String");
var c = Class.forName("android.os.SystemProperties");
var get = c.getMethod("get", String.class, String.class);
result = get.invoke(c, data, "Error");
return result;
}
Where data is a string of the system property I want.
I am using it to extract and match a serial number from a Samsung device that is a System Property call "ril.serialnumber" or "sys.serialnumber". Now I can use the above function to do what I was using the JAR file for. Just thought I'd share in case anyone else needed something similar.
It is because android.os.SystemProperties is not class you can import. Check the android documentation at https://developer.android.com/reference/android/os/package-summary.html
You could use
var build = require('android.os.Build');
console.log(build.SERIAL);
to access the serial number.

Where to place sqlite-jdbc-3.7.2.jar in eclipse to make it work?

Placing sqlite-jdbc-3.7.2.jar in the libs folder causes eclipse to run into a heap error. Placing it in a separate folder and adding it to the build path causes class not found errors.
Adding it to the exported jars list causes the heap error as well.
Any ideas?
Quick answer, it'll fail no matter where you place it. The problem is that some native jar libraries are just not supported by Android. We may have to depend on some developers to port some better resolutions.
In this case (while I'm sure there are others) you can use, instead SQLDroid.jar. I have tested it and so far it performs just as the normal sqlite-jdbc-3.7.2.jar does in native java programs.
I'm sure (as I mentioned in my comment to cYrixmorten, the purpose of choosing to use a native sqlite support is to have portability for your other sqlite databases, as well as having the native CRUD support.
A tested working example using SQLDroid.jar:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
Code Segment:
public void checksqlite()
{
try {
String db = "jdbc:sqlite:" + getFilesDir() + "/test.db";
Class.forName("org.sqldroid.SQLDroidDriver");
Connection conn = DriverManager.getConnection(db);
Statement stat = conn.createStatement();
stat.executeUpdate("create table primes (number int);");
stat.executeUpdate("insert into primes values (2);");
stat.executeUpdate("insert into primes values (3);");
stat.executeUpdate("insert into primes values (5);");
stat.executeUpdate("insert into primes values (7);");
ResultSet rs = stat.executeQuery("select * from primes");
boolean b = rs.first();
while (b) {
Log.d("JDBC", "Prime=" + rs.getInt(1));
b = rs.next();
}
conn.close();
} catch (Exception e) {
Log.e("JDBC", "Error", e);
}
}
The links and comments provided by cYrixmorten was invaluable in helping me to find this resolution. I hope others can benefit from it.

Log4j log files not created in android

I am using Log4j to log data in my android application. I have configured the log4j with the help of the following class, but the log files are not getting created.
console logging is enabled, maxfilesize and maxbackupsize are also good. please let me know what i am missing here.
public class ConfigureLog4J {
static LogConfigurator logConfigurator = new LogConfigurator();
private static final int maxFileSize = 1024 * 5; // 100KB
public static final int maxBackupSize = 2; // 2 backup files
public static final String LOG_FILE_NAME = "bitzer.log";
private static HashMap<Integer, Level> logLevelMap = new HashMap<Integer, Level>();
static {
logLevelMap.put(0, Level.OFF);
logLevelMap.put(1, Level.ERROR);
logLevelMap.put(2, Level.INFO);
logLevelMap.put(3, Level.WARN);
logLevelMap.put(4, Level.DEBUG);
logLevelMap.put(5, Level.ALL);
}
public static void startWithLogLevel(int logLevel) {
logConfigurator.setFileName(getLogFileName());
logConfigurator.setRootLevel(getLevelFromInt(logLevel));
logConfigurator.setUseFileAppender(true);
logConfigurator.setUseLogCatAppender(isConsoleLoggingEnabled());
logConfigurator.setMaxFileSize(getMaxFileSize());
logConfigurator.setMaxBackupSize(maxBackupSize);
// Set log level of a specific logger
// logConfigurator.setLevel("org.apache", Level.ERROR);
logConfigurator.setResetConfiguration(true);
logConfigurator.configure();
}
private static long getMaxFileSize() {
return CompanySettings.getInstance().getValueAsInteger(R.string.max_log_size);
}
private static boolean isConsoleLoggingEnabled() {
return CompanySettings.getInstance().getValueAsBoolean(R.string.consoleLoggingEnabled);
}
private static Level getLevelFromInt(int newLogLevel) {
return logLevelMap.get(newLogLevel);
}
public static String getLogsDirectory() {
if(AppData.getInstance().getContext()!=null)
{ String packageName = AppData.getInstance().getContext().getPackageName();
System.out.println("sundeep package name is not null and it's"+packageName);
return "data/data/" + packageName + "/logs/";
}
return null;
}
public static String getLogFileName() {
return getLogsDirectory() + LOG_FILE_NAME;
}
}
SLF4J Overview
I highly recommend you use SLF4J, which is log4j's "older brother" of sorts; the same developers who made log4j made SLF4J to address the shortcomings of log4j.
The difference is, whereas log4j is a full-fledged logging framework, SLF4J is a facade which you use directly in your Java code. The facade aspect allows you to plugin a concrete logging implementation — such as log4j, logback, Android's Log utility, etc. — at runtime.
It allows you to write code that can be used between different projects without having to go through your code and convert your logging statements to use the target project's logging framework. If you have several thousand lines of code which use log4j, but the target you're importing them into uses Apache Commons logging, you'll soon find yourself with a headache if you manually make the changes... even with the assistance of a capable IDE.
Using log4j in Android
There's a great Android library for logging to log4j — as well as many other logging frameworks as well — called android-logging-log4j. Check out the very excellent section on "Using log4j over slf4j", which is the route I take in my Android projects.
Examples from my own projects
Here are some examples from my own projects, such as my Awnry News & Weather app. (Yeah, shameless plug :P)
Required JARs on classpath
Basically these are the JARs I'll typically have in my project's classpath (version numbers vary as new releases come about, of course).
android-logging-log4j-1.0.3.jar
log4j-1.2.17.jar
slf4j-api-1.7.6.jar
slf4j-log4j12-1.7.6.jar
Instantiating a class's logger
And here's how I instantiate my general logger in each of my classes that require logging:
package com.awnry.android.naw;
...
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
public class NawApplication extends Application
{
private static final Logger log = LoggerFactory.getLogger(NawApplication.class);
As you can see, I'm only referencing SLF4J's Logger and LoggerFactory interfaces, even though the actual logging may eventually be accomplished using log4j or Android's Log.
That's the beauty of SLF4J's facade design: You aren't tied down to any specific logging implementation/framework; you can change your mind in the future without having to change a line of your code. If you're using log4j over SLF4J now, but in the future you want to use the Apache Commons Logging framework all you have to do is switch out the SLF4J-to-log4j bridge to a SLF4J-to-ACL bridge, and none of your Java code will be any wiser as it only calls SLF4J interfaces. The time-honored adage to code to an interface, not an implementation holds true once again, and SLF4J is a superb example of that.
Configuring the Android app's logging
In my Application.onCreate() method, I configure my logging like this:
#Override
public void onCreate()
{
...
String logFile = getFilesDir().getAbsolutePath() + File.separator + "logs" + File.separator + "debug.log";
log.info("Application log file: " + logFile);
LogConfigurator logConfigurator = new LogConfigurator(logFile, Level.TRACE);
logConfigurator.configure();
...
}
This part is actually optional, I believe. In my case I do this because I use the ACRA library to help catch unexpected program crashes and report the details back to me for debugging, so you might not need to define your android-logging-log4j's LogConfigurator as I do here.
Why you are using log4j.
There are efficient Log utility is available specially designed for android.
Use LogCat. Its very simple to use and standard way of putting log in your android app.

Categories

Resources