8. June 2019

How to add custom mapping of a hostname to IP address in Android Emulator

There is a simple trick which allows your application to resolve a hostname to IP address defined by you even in cases when you do not have access to DNS server. This trick could be also used when you’re connected via VPN and the emulator is not able to resolve DNS record available only in private network.

Let’s add following hostname record which should be resolved by application on Android:

192.168.1.2 test.georgik.rocks

First of all, you need to start your AVD with parameter ‘-writable-system’, because emulator’s filesystem is by default read-only.

Let’s get names of available AVDs.

Example for macOS:

cd ~/Library/Android/sdk/tools
./emulator -avd -list

The output might look like:

Pixel_2_API_23
Pixel_2_API_24

Start the emulator:

./emulator -avd "Pixel_2_API_23" -writable-system

You should see the following warning:

emulator: WARNING: System image is writable

The emulator will start. Now you need to remount the filesystem so it will become writable. This could be done via adb tool which is in platform-tools directory.

Version for macOS:

cd ~/Library/Android/sdk/platform-tools
./adb remount

Now you can start the shell and append the line with configuration to /etc/hosts:

./adb shell 'echo "192.168.1.2 test.georgik.rocks" >> /etc/hosts'

Now you can test the configuration by ping:

root@generic_x86_64:/etc # ping test.georgik.rocks
PING test.georgik.rocks (192.168.1.2) 56(84) bytes of data.

7. June 2019

How to solve Android Emulator java.io.FileNotFoundException open failed: EACCES (Permission denied)

Following error in Android application is very annoying and you may waste several hours by hunting the root cause:

D/file: java.io.FileNotFoundException: /storage/emulated/0/Download/20190604_084533.jpg: 
open failed: EACCES (Permission denied)

It might occur even when the manifest is correct and contains proper permission:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

Here is sample code which will pass on file existence check, but the execution will fail on readBytes:

var file:File = File("/storage/emulated/0/Download/20190604_084533.jpg")
if (file.exists()) {
    val content:ByteArray;
    Log.d("file", "exist")
    try {
        content = f.readBytes()
     } catch (FileNotFoundException) {
        Log.d("file", e.toString())
     }

} else {
     Log.d("file", "does not exist")
}

To fix this problem it is necessary to go to Settings – Apps – My App – Permission.

Access to Storage is probably disabled. Tap Storage to enable it:

With enabled Storage option, the application was able to read the file.

To solve this problem in a proper way, it’s necessary to add a request for permission to the code. Here is a sample in Kotlin:

val MY_READ_EXTERNAL_REQUEST : Int = 1
if (checkSelfPermission(
    Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), MY_READ_EXTERNAL_REQUEST)
}

You can find more details about requesting permissions in Android documentation.

23. April 2019

Android Studio Unresolved reference: activity_main – R.layout and R.id

You can easily run into mysterious errors with Android Studio. Here is one.

Suddenly all references related to R.layout or R.id stopped to work and build failed with a message like this:

Compilation error. See log for more details
Unresolved reference: activity_main
Unresolved reference: url_edittext
Unresolved reference: update_button

The code looked like this:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

I tried clean, builds, rebuilds. Nothing helped. The problem was caused by simple import which accidentally occurred in Activity file:

import android.R

After removing this line the whole project was working again and even code hinting was correct.

15. April 2019

Android Emulator application crash: Chromium WebView package does not exist

Android application with WebView might crash with a strange error in Android Emulator:

E/WebViewFactory: Chromium WebView package does not exist
    android.webkit.WebViewFactory$MissingWebViewPackageException: Failed to load WebView provider: No WebView installed
        at android.webkit.WebViewFactory.getWebViewContextAndSetProvider(WebViewFactory.java:334)
        at android.webkit.WebViewFactory.getProviderClass(WebViewFactory.java:398)
        at android.webkit.WebViewFactory.getProvider(WebViewFactory.java:211)
....

Check the definition of Virtual Device. It’s very likely that your device is using plain Android target which does not contain the WebView. You have to create Virtual Device which contains Google APIs.

Click Create Virtual Device. Select an image with “Google APIs“:

Now you can start the application in the newly created emulator with Google APIs.

The application should run without a problem.

13. June 2018

Android Studio NDK could not start mips64el-linux-android-strip

If you’re using Android Studio to build C++ application with NDK you might encounter following error during build:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:transformNativeLibsWithStripDebugSymbolForDebug'.
...
Caused by: java.io.IOException: Cannot run program ".../Android/Sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/linux-x86_64/bin/mips64el-linux-android-strip": 
error=2, No such file or directory

The problem is caused by the upgrade of NDK in Android Studio to NDK v17. This version has a different structure of tools. It’s not compatible with Android Experimental Plugin v0.11.

The directory which should contain binary of tools contains just file NOTICE-MIPS64:

This mips64el-linux-android-4.9 directory exists to make the NDK compatible with the Android
SDK's Gradle plugin, version 3.0.1 and earlier, which expects the NDK
to have a MIPS64 toolchain directory.

The solution is to download NDK v16 from NDK older releases. Extract it and replace former ndk-bundle directory.

Commands for macOS or Linux users:

cd ~/Android/Sdk
unzip ~/Downloads/android-ndk-r16b-linux-x86_64.zip
mv ndk-bundle ndk-bundle-v17
mv android-ndk-r16b ndk-bundle

If you’re Windows user the location of NDK is typically in your profile AppData\Local\Android. Do not forget to unblock the ZIP after downloading (right click, Properties, Unblock, Ok)

Commands for Windows users:

cd ~\AppData\Local\Android\Sdk
unzip ~\Downloads\android-ndk-r16b-windows-x86_64.zip
mv ndk-bundle ndk-bundle-v17
mv android-ndk-r16b ndk-bundle

Start Android Studio. It should prompt you to update NDK. Do not confirm this request, it will replace NDK with v17. You should see the following screen in SDK Manager:

You can find related sample source code at GitHub in sdl2-android-example – branch gradle-4-using-android-experimental-plugin repository. Further articles about SDL2 and Android are available under the tag SDL2.

Since Google is moving away from Gradle Android Experimental plugin you might consider using Gradle 5 + CMake. The migration is relatively easy and it could save you the trouble of being stuck with old NDK. You need to create CMakeLists.txt instead of build.gradle for C/C++ parts of the code. Example of migration is at GitHub – sdl2-android-example – PR#6.