Category: Uncategorized

Android – Reduce the size of your APK files

Android – Reduce the size of your APK files

If it is one thing that I hate – it is apps that are HUGE downloads for really simplistic functionality.

40MB for an app that just accesses some messages and has hardly any images, what is it doing??

313

I have recently had quite an obsession trying to reduce my app size and have managed to shave off 6MB with a few optimisations (Yay right?!!!! 😃). I thought I would share some tips on how to reduce your Android APK file size:

  1. Use ProGuard: this will obfuscate your code and reduce the app size. [1]
  2. Enable the following with gradle:
    • minifyEnabled – this will get rid of unused code.
    • shrinkResources – this will get rid of unused resources such as layouts or strings that are not referenced in your app.
      buildTypes {
      
              release {
                  shrinkResources true
                  minifyEnabled true
                  proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),'proguard-project.txt'
                  signingConfig signingConfigs.config
      
              }
          }
      
  3. Make use of split APKs. This is especially useful if you are using native libraries. The native libraries can be quite large and making a user download an x86 library when their device is ARMv7 is pointless. Strip that out. [2]
  4. Check your images. If there are any large bitmaps, chances are you can reduce the size without losing much detail in the image. If possible, use JPEGs instead of PNGs as they are generally smaller.[3]
  5. Consider using Vector Drawables instead of PNGs for every density bucket. This will reduce the number of files needed and the images won’t degrade in quality.[4]
  6. Don’t use images if you don’t need to. Gradient backgrounds, shapes or colours can be achieved with XML instead.[5]
  7. Consider the libraries you use. If a library is massive and you are only using one or two functions you should find an alternative smaller option. Look through your code to see if there are any unused JAR files or unused code and remove that too.

Be careful when doing the things listed above, make sure you test thoroughly after applying these changes as it could break parts of your app. It could get rid of resources or code that might be used.

What do you do to reduce the size of your APKs?

Links:
  1. ProGuard Documentation
  2. Split APKs
  3. PNG vs JPG vs SVG
  4. Vector Asset Studio
  5. Drawable Resources
Google Cloud Test Lab – and why you should care about it.

Google Cloud Test Lab – and why you should care about it.

If you have worked on any really popular app you will know the pains involved in development: thousands of different devices, different configurations, or different versions of Android.

Now we may think that we have the most of these devices covered but the inevitable will happen. You are bound to have some guy with some weird form factor of Android that you can’t get your hands on or maybe cant afford.

I know I have seen some weird crash logs appearing in production and never once picked up in development, QA or UAT.

I mean, have you ever tried running your app in the Drakensberg where 2G is a luxury?

Phone frustration

Cue Google Cloud Test Lab.

What is it exactly?

It is basically a farm of physical and virtual devices waiting for you to take advantage of. Many different devices with different languages, Android versions, orientations are available in both physical or virtual forms.

What can I do with it?

You can do two different things:

  1. You can run a Robo test. Which requires no code to activate. Simply upload your APK file, choose your devices to test on and see the results.
Google Cloud Test Lab - Selecting devices to run tests on.
Running a Robo test – Selecting devices and configuration options to run with.

It is sort of like unleashing a small child on your app but now you will be able to see how the crashes were produced.

toddlerphone

2. You can also run Instrumentation tests that you have written with Espresso or Robotium and see the results of your tests running.

Example execution of Instrumentation tests showing some failing and some passing.
Example execution of Instrumentation tests showing some failing and some passing.

Once your tests have run, you will see detailed reports for every device, including the following information:

  • Device Logs
  • Screenshots from the device
  • Videos of the execution
  • Activity Map which will indicate what was pressed to get to the different screens.

    Example of the Activity Map from a Robo Test
    Example of the Activity Map from a Robo Test
How can I use it?

It is only in Beta at the moment but you can sign up for updates and get notified when its available for everyone.

Why should I care about this?

Android Developers have to deal with over 6000 different devices in the real world. Not everyone owns the latest phone and has the greatest internet connection. Having a large cupboard filled with different Android devices can get quite costly and difficult to achieve.

Google Cloud Test Lab service is bound to pick up issues that you may have missed with your own testing on your own devices.

If you want to get updates about Google Cloud Test Lab visit the site here:

Google Cloud Test Lab

Four Apps I Can’t Live Without

Four Apps I Can’t Live Without

I’m always really curious to know what apps people use on a daily basis, and what about those apps makes them so awesome?

I have a couple of apps that have just slotted so easily into my everyday life, that I don’t even realise I am using them.

Here they are:

PushBullet

pushbullet

https://www.pushbullet.com/

This app is integral to using an Android phone, if you haven’t installed this app, you are not taking advantage of all of your phone’s capabilities.

Basically it allows you to see notifications from your phone, on your computer. It pushes notifications to your computer and you even have the ability to interact with some of the notifications. As an example when you are using TuneIn Radio on your phone, you can pause and play the music on your phone from your computer. You are even able to see your phone ringing, on your computer. Rad right?

The app also allows you to easily send links, text or files to your devices from your computer using Google Chrome. Gone are the days of emailing yourself links & files to get them on your phone. The Chrome extension also allows you to send SMS messages from your computer on your phone (if you are all old school cool and like sending a good old text message).

This is definitely one of my favourite apps, and I feel like Google should include this functionality in their operating systems by default, because it’s so cool.

PushBullet is also really easy to set up: (https://www.pushbullet.com/get-started)

Android Store Download

iTunes Store Download

 

IFTTTif

https://ifttt.com/

You know those painful tasks that should be easy but aren’t? Like every time you post a photo to Instagram, you have to go to Twitter and upload the same picture, just so it will appear nicely in your Twitter feed?

Well IFTTT can handle these kinds of things for you. The whole concept is “If this, then that”. Basically, you can create recipes (or use ones already created by other people) that will result in an action if certain conditions occur. As an example, you can set the app to save all your instagram photos to dropbox, which means that every time you upload a new photo to instagram, it will also save that photo in a specific location on dropbox, without you having to do anything.

This app really appeals to the developer in me. You can also buy these cool Philip Hue Lights that can turn on when you arrive home. My only gripe with this app is that it is a bit buggy, sometimes the recipes don’t run and that makes me a bit sad.

App Store Downloads:

Android Play Store Download

iTunes Store Download

CloudMagiccloudmagic

https://cloudmagic.com/

Apparently all companies have decided that Microsoft Exchange Mail is the best thing ever. I tend to disagree, I feel like we should all be using Google Apps for business, but for those of us who are subjected to using Exchange Mail every day, this app is really useful.

It is one of the best mail apps that integrates quite seamlessly with an exchange server. I love the look of the app, it’s stability and reliability. You can also connect multiple accounts of different types: Gmail, Exchange, Outlook, Yahoo, Office 365 , iCloud.

Best of all? The app is free and doesn’t have any adverts. One thing that is not so cool, you can’t view your calendar and event invites are still a bit weird in the app. But nevertheless, a great alternative to Microsoft’s attempt at Outlook for Android.

App Store Downloads:

Android Play Store

iTunes Store Download

TuneIn Radiotunein

I hate downloading music, especially because you need to know what the song names are and then there is the whole effort of finding the songs online (usually on some obscure website, with a million ads).

It frustrates me, so I normally end up listening to the same songs over and over again. Introducing TuneIn Radio. I never need to download another song again, or rip MP3s from a CD (Is this even still a thing? I mean, how old school can you get?)

TuneIn radio, has a massive list of radio stations you can choose from, that play all different types of music. Including local stations such as 5fm, 94.7, Metro FM. My current favourite – Capital London. There is a wide variety of stations to listen to, and every music taste is catered for (Including some delightful tunes by Tibetan Throat Singers)

App Store Downloads:

Android Play Store

iTunes Store 

 

What apps can’t you live without?

A Robotic Guide Dog and Why its a Bad Idea

A Robotic Guide Dog and Why its a Bad Idea

For my honours dissertation, I decided to undertake a project involving the programming of a Lego Mindstorm Robot. Granted, this blog post is a bit late (2  years later!), but I figured I’d share my experiences so that someone doesn’t attempt the same 🙂 .The outcome of the application was to have a robotic “guide dog” that a blind user would be able to follow. This was purely a concept, as anyone following this robot would probably have died 3 times over 🙂 But a concept none the less.

Lessons Learnt from this project:

  • Microsoft Robotics Studio is a terrible idea.
  • Lego Mindstorm robots are pretty pathetic in their abilities, they are good for basic stuff, but as soon as you want to go into complex object avoidance algorithms, they pretty much fail dismally.
  • Real world vs Theoretic world are two completely different things. When somebody says “Theoretically this should work”, DO NOT believe them.
  • Its better to simulate real life than to actual be in it.

In the end I had 3 components to the system, in the end.

1. An android application that would take in voice commands and determine whether the robot should stop, turn around, left, right etc.

2. The robotic dog

3. A desktop application which issued commands to the robot via Bluetooth, and connects to the android phone via bluetooth.

Ideally, I would have liked to have the application running entirely on the robot, but unfortunately the Lego Mindstorm robot had a tiny amount of memory (maybe the choice of a raspberry pi would have been a better option?).
So the lesson learnt from this experience, a robotic dog is a bad idea for a blind person, and perhaps something like a ultrasound device that you wear would be a better choice than a physical robot that a user would have to carry.

Regardless, below is an example video of how the robot detected obstacles and moved around them.

This video wasn’t the final version, as the final version had the voice commands controlling the robot 😀

Calories Burnt Calculation for Walking or Running in Java

Calories Burnt Calculation for Walking or Running in Java

Its surprisingly difficult to find a calorie calculation for Java for performing a number of steps at a certain speed. Based on the Compendium of Physical Activities (https://sites.google.com/site/compendiumofphysicalactivities/corrected-mets )  and using Corrected METS, I have converted the formulas on their website into Java code! I found the website particularly difficult to read as it did not have brackets in the right places to ensure that the calculations were correct. Hopefully I can save someone the hassle of having to wonder what is going on with all their formulas.

/**
     * Calculated the energy expenditure for an activity. Adapted from the following website https://sites.google.com/site/compendiumofphysicalactivities/corrected-mets
     *
     * @param height               The height in metres.
     * @param age                  The date of birth.
     * @param weight               The weight of the user.
     * @param gender               The gender of the user.
     * @param durationInSeconds    The duration of the activity in seconds.
     * @param stepsTaken           The steps taken.
     * @param strideLengthInMetres The stride length of the user
     * @return The number of calories burnt (kCal)
     */
    public static float calculateEnergyExpenditure(float height, Date age, float weight, int gender, int durationInSeconds, int stepsTaken, float strideLengthInMetres) {

        float ageCalculated = getAgeFromDateOfBirth(age);

        float harrisBenedictRmR = convertKilocaloriesToMlKmin(harrisBenedictRmr(gender, weight, ageCalculated,   convertMetresToCentimetre(height)), weight);

        float kmTravelled = calculateDistanceTravelledInKM(stepsTaken, strideLengthInMetres);
        float hours = UnitConverter.convertSecondsToHours(durationInSeconds);
        float speedInMph = UnitConverter.convertKilometersToMiles(kmTravelled) / hours;
        float metValue = getMetForActivity(speedInMph);

        float constant = 3.5f;

        float correctedMets = metValue * (constant / harrisBenedictRmR);
        return correctedMets * hours * weight;
    }
/**
     * Gets a users age from a date. Only takes into account years.
     *
     * @param age The date of birth.
     * @return The age in years.
     */
    private static float getAgeFromDateOfBirth(Date age) {
        Calendar currentDate = Calendar.getInstance();
        Calendar dateOfBirth = Calendar.getInstance();
        dateOfBirth.setTime(age);

        if (dateOfBirth.after(currentDate)) {
            throw new IllegalArgumentException("Can't be born in the future");
        }
        int currentYear = currentDate.get(Calendar.YEAR);
        int dateOfBirthYear = dateOfBirth.get(Calendar.YEAR);
        int age2 = currentYear - dateOfBirthYear;
        int currentMonth = currentDate.get(Calendar.MONTH);
        int dateOfBirthMonth = dateOfBirth.get(Calendar.MONTH);

        if (dateOfBirthMonth > currentMonth) {
            age2--;
        } else if (currentMonth == dateOfBirthMonth) {
            int currentDay = currentDate.get(Calendar.DAY_OF_MONTH);
            int dateOfBirthDay = dateOfBirth.get(Calendar.DAY_OF_MONTH);
            if (dateOfBirthDay > currentDay) {
                age2--;
            }
        }
        return age2;
    }
public static float convertKilocaloriesToMlKmin(float kilocalories, float weightKgs) {
        float kcalMin = kilocalories / 1440;
        kcalMin /= 5;

        return ((kcalMin / (weightKgs)) * 1000);
    }
 public static float convertMetresToCentimetre(float metres) {
        return metres * 100;
    }
  public static float calculateDistanceTravelledInKM(int stepsTaken, float entityStrideLength) {
        return (((float) stepsTaken * entityStrideLength) / 1000);
    }
/**
     * Gets the MET value for an activity. Based on https://sites.google.com/site/compendiumofphysicalactivities/Activity-Categories/walking .
     *
     * @param speedInMph The speed in miles per hour
     * @return The met value.
     */
    private static float getMetForActivity(float speedInMph) {
        if (speedInMph < 2.0) {
            return 2.0f;
        } else if (Float.compare(speedInMph, 2.0f) == 0) {
            return 2.8f;
        } else if (Float.compare(speedInMph, 2.0f) > 0 && Float.compare(speedInMph, 2.7f) <= 0) {
            return 3.0f;
        } else if (Float.compare(speedInMph, 2.8f) > 0 && Float.compare(speedInMph, 3.3f) <= 0) {
            return 3.5f;
        } else if (Float.compare(speedInMph, 3.4f) > 0 && Float.compare(speedInMph, 3.5f) <= 0) {
            return 4.3f;
        } else if (Float.compare(speedInMph, 3.5f) > 0 && Float.compare(speedInMph, 4.0f) <= 0) {
            return 5.0f;
        } else if (Float.compare(speedInMph, 4.0f) > 0 && Float.compare(speedInMph, 4.5f) <= 0) {
            return 7.0f;
        } else if (Float.compare(speedInMph, 4.5f) > 0 && Float.compare(speedInMph, 5.0f) <= 0) {
            return 8.3f;
        } else if (Float.compare(speedInMph, 5.0f) > 0) {
            return 9.8f;
        }
        return 0;
    }

    /**
     * Calculates the Harris Benedict RMR value for an entity. Based on above calculation for Com
     *
     * @param gender   Users gender.
     * @param weightKg Weight in Kg.
     * @param age      Age in years.
     * @param heightCm Height in CM.
     * @return Harris benedictRMR value.
     */
    private static float harrisBenedictRmr(int gender, float weightKg, float age, float heightCm) {
        if (gender == Entity.GENDER_FEMALE) {
            return 655.0955f + (1.8496f * heightCm) + (9.5634f * weightKg) - (4.6756f * age);
        } else {
            return 66.4730f + (5.0033f * heightCm) + (13.7516f * weightKg) - (6.7550f * age);
        }

    }