Лучшие статьи и кейсы стартапов
Включить уведомления
Дадим сигнал, когда появится
что-то суперстоящее.
Спасибо, не надо
Вопросы Проекты Вакансии
Платформа мгновенных уведомлений.
Рекомендуем
Продвинуть свой проект
Лучшие проекты за неделю
37
Битрикс24

Битрикс24

www.bitrix24.ru

28
Отследить-посылку

Отследить-посылку

отследить-посылку.рф

13
WebResidentTeam

WebResidentTeam

webresident.agency

12
Логомашина

Логомашина

logomachine.ru

11
Devicerra

Devicerra

devicerra.com

9
ADN Digital Studio

ADN Digital Studio

adn.agency

9
Aword

Aword

Приложение для изучения английских слов

9
Eczo.bike

Eczo.bike

www.eczo.bike

9
GIFTD

GIFTD

giftd.tech

7
Flowlu

Flowlu

flowlu.ru

Показать следующие
Рейтинг проектов
Подписывайтесь на Спарк во ВКонтакте

Оптимизация Android приложения + защита передачи Callback

340 0 В избранное Сохранено
Авторизуйтесь
Вход с паролем
Достаточно крупное обновление исправляющее ошибки в андроид клиенте и улучшающее безопасность получения ID пользователя. В статье также будет описаны методы решения проблем. Описан алгоритм кэширования изображений, думаю многим будет полезно.

Опишу в стиле проблемы и её решение.

Обрезаются иконки

Ко мне обращались с проблемой, что на Android 4.* иконки обрезаются. Если точнее, на старых версих не было автоматической подгонки иконок.

Решилось это просто:

if(icon != null){
    Resources res = getApplicationContext().getResources();
    int height = (int) res.getDimension(android.R.dimen.notification_large_icon_height);
    int width = (int) res.getDimension(android.R.dimen.notification_large_icon_width);
    int realwidth=icon.getWidth();
    int realheight=icon.getHeight();
    if(realwidth>realheight){
        height=height * realheight / realwidth;
    }else{
        width=width * realwidth / realheight;
    }
    icon=Bitmap.createScaledBitmap(icon, width, height, true);
}

Выше представлен алгоритм адаптивного изменения иконки под устройство. При том используется фильтрация, поэтому параллельно с этим мы еще и улучшили качество отображения иконок на более новых версиях Android.

Приложение качает по 100 МБ трафика в месяц

Эту проблему уже заметил я, и я посчитал, что она очень серьезная. Также в неё можно включить такие проблемы:
  1. Долгая доставка уведомления при загрузке картинки через нестабильное соединение
  2. Отсутствие иконки при плохом соединении
  3. Отсутствие иконки в режиме экономии энергии.

Про последнее хочу рассказать подробнее. Дело в том, что Android, в новых версиях, в режиме энергосбережения, отключает фоновую передачу всех не системных приложений. Это приводит к тому, что уведомление приходит, а вот иконку мы загрузить не можем.

Решение: создать алгоритм кэширования.

Сначала я долго бился над тем, чтобы алгоритм использовал стандартные средства кэша HTTP.

connection.setUseCaches(true);

Я нашел даже решение для переопределения алгоритма кэширования, т.к. стандартного не было, и оно вроде как работало, за одним исключением - в случае если сети нет - иконка все равно не загрузится. То есть Android блокировал именно все HTTP запросы, даже если идет проверка кэширования.

Тогда я написал свой метод, который проверяет наличие md5-имени файла в папке кэша. И если он есть, то использует его. Сеть вообще не используется. Это достаточно жесткое кэширование, то есть для смены изображения, нужно всегда менять его название, иначе будет загружаться старое.

public Bitmap getBitmapFromURL(String strURL) {
    Bitmap myBitmap;
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inPreferredConfig = Bitmap.Config.RGB_565;
    File file = new File(cacheDir, md5(strURL));
    FileInputStream finput=null;
    if (file.exists()) {
        try {
            finput = new FileInputStream(file);
            myBitmap=BitmapFactory.decodeStream(finput, null, options);
            finput.close();
            return myBitmap;
        } catch (IOException e){
            return BitmapFactory.decodeResource(
                    getResources(), R.drawable.gcm_cloud, options);
        }
    }

    try {
        URL url = new URL(strURL);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        //connection.setUseCaches(true);
        connection.setDoInput(true);
        connection.connect();

        if (connection.getContentLength() < 524288){
            InputStream input = connection.getInputStream();

            FileOutputStream output = new FileOutputStream(file);
            int bufferSize = 1024;
            byte[] buffer = new byte[bufferSize];
            int len = 0;
            while ((len = input.read(buffer)) != -1) {
                output.write(buffer, 0, len);
            }
            output.close();
            finput = new FileInputStream(file);
            myBitmap = BitmapFactory.decodeStream(finput, null, options);
            finput.close();
        }else{
            myBitmap=BitmapFactory.decodeResource(
                getResources(), R.drawable.gcm_cloud, options);
        }
        return myBitmap;
    } catch (IOException e) {
        //e.printStackTrace();
        return null;
    }
}

public static final String md5(final String s) {
    final String MD5 = "MD5";
    try {
        // Create MD5 Hash
        MessageDigest digest = java.security.MessageDigest
                .getInstance(MD5);
        digest.update(s.getBytes());
        byte messageDigest[] = digest.digest();

        // Create Hex String
        StringBuilder hexString = new StringBuilder();
        for (byte aMessageDigest : messageDigest) {
            String h = Integer.toHexString(0xFF & aMessageDigest);
            while (h.length() < 2)
                h = "0" + h;
            hexString.append(h);
        }
        return hexString.toString();

    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return "";
}

Выше я описал итоговый алгоритм генерации битмапа с проверкой кэша и MD5 функцию, которую нашел в сети.

Также в алгоритме используется ограничение размера картинки в 512 килобайт.

Итог: при подписке на 20 каналов пользователь не грузит больше по 1-5 мегабайт в день. Также уведомления приходят намного быстрее, а иконки отображаются даже если сети нет, конечно же при условии, что канал не использует каждый раз новые иконки.

Любой может внедрить callback ссылку на свой сайт и "привязать" свои устройства к чужим аккаунтам

Странно что мы не додумались до этого ранее, но это так. Мы добавили новые методы защиты.

Новый адрес такой: АДРЕС?pushalluserid=ID&time=UNIXTIME&sign=ПОДПИСЬ.

То есть в GET вам будет передан параметр "pushalluserid" с ID пользователя, а также параметры для проверки.

Для проверки подписи используйте md5($key.$pushalluserid.$time.$ipAddress).

Где ipAddress:

$ipAddress = $_SERVER['REMOTE_ADDR'];

Где $key - ключ вашего канала. Где $time - UNIXTIME.

Вы можете сами установить необходимый уровень проверки, к примеру после проверки времени и IP считать ключ валидным 1 минуту. Также следите за тем, чтобы время на вашем сервере было точное. При желании можно считать ссылку валидной вообще секунд 5.

Также остается работать обратная совместимость. То есть после введения этого метода безопасности ваши текущие приложения продолжают работать. Но вам нужно как можно быстрее реализовать защиту на своей стороне.

Как итог имеем проверку и безопасность, реализованную без дополнительных запросов.

+2
Комментариев еще не оставлено
Выбрать файл
Читайте далее
Загружаем…
Блог проекта
Расскажите историю о создании или развитии проекта, поиске команды, проблемах и решениях
Написать
Личный блог
Продвигайте свои услуги или личный бренд через интересные кейсы и статьи
Написать