Лучший способ получить бесплатную версию Android-приложения

У меня уже есть бесплатное приложение на Android Market, но я хочу добавить платную версию с лучшими функциями. Я не могу загрузить то же самое с некоторыми измененными константами, чтобы разблокировать эти функции, поскольку Market говорит мне, что у меня уже есть приложение с этим именем пакета на рынке.

Какой самый чистый способ сделать это?

Ответ 1

Android SDK официально рассматривает проблему с общей или общей базой кода с чем-то, называемым библиотечным проектом.

http://developer.android.com/tools/projects/index.html

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

При сборке проект библиотеки объединяется с любым из ваших релизов, что вам и нужно.

Исходный код примера Android SDK содержит проект TicTacToe, который поможет вам начать работу с библиотечными проектами.

Удачи.

Daniel

Ответ 2

Существует несколько подходов, но вы обычно не видите недостатков, пока не попробуете их сами. Вот мои впечатления:

  • Приложение Unlocker. Это очень просто реализовать, создать новое приложение, которое действует как лицензия: ваше оригинальное приложение должно проверить, соответствует ли подпись приложения для разблокировки вашего приложения (если да, то на вашем устройстве имеется разблокировка, иначе нет); ваш unlocker должен запросить загрузку вашего бесплатного приложения, если он не установлен, в противном случае запустите его и удалите его значок запуска.

    Плюсы: просты в реализации, и есть только одна база кода для поддержки.
    Минусы: говорится, что пользователи иногда путают эту модель, они просто не понимают, почему у них есть две иконки запуска или что они только что загрузили. Удаление значка пусковой установки громоздко, изменения видны только в том случае, если устройство перезагружено. Кроме того, похоже, что вы не сможете использовать API лицензирования Google (LVL), потому что ваше бесплатное приложение не может выполнять запросы на лицензирование от имени вашего платного приложения для разблокировки. Любое обходное решение для этого последнего приводит к плохому опыту пользователя.

  • Покупка в приложении. Это легко реализовать, если у вас есть IAP в вашем коде в любом случае, в противном случае потребуется некоторое время, чтобы все исправить.

    Плюсы: существует только одна кодовая база для поддержания и покупки потока для пользователя.
    Минусы: Говорят, что пользователи обеспокоены тем, является ли их покупка "постоянным", а это означает, что они смущены тем, могут ли они использовать функции pro, если они позже установили приложение на другое устройство или переустановили его.

  • Бесплатные и платные версии с проектом общей библиотеки. Это не должно быть сложной задачей для кода и кажется логичным решением иметь единую кодовую базу, содержащую большую часть вашей логики приложения, и поддерживать только различия.

    Плюсы: пользователи менее смущены этой моделью, но, вероятно, они обеспокоены тем, будут ли их предпочтения потеряны, если они начнут использовать платную версию.
    Минусы: Java/Eclipse в моем опыте не очень дружелюбен, когда дело доходит до библиотек. Потребуется некоторое время, чтобы правильно настроить проекты, но все равно будет запутывать, как все это работает, что делать, в каком манифесте, что происходит с ресурсами и т.д. Вы столкнетесь с проблемами сборки с неправильно сконфигурированными проектами, создавайте проблемы с ресурсы не будут найдены (проект библиотеки не будет "видеть" уже упомянутые ресурсы, поэтому вам придется редактировать ссылки поочередно). Кроме того, в этой модели не поддерживаются файлы активов, что означает, что вам нужно будет сделать некоторые трюки с символикой, копированием или другой магией, которые просто добавят к ужасному беспорядку, который уже стал вашим проектом "единой кодовой базы". И когда ваш проект, наконец, строится, вам просто нужно держать пальцы скрещенными, чтобы все работало так, как ожидалось, быть готовым к отсутствию изображений и скрытых ошибок, которые нужно искать. И, конечно же, вам нужно будет предоставить своим пользователям удобный способ перенести свои предпочтения в платную версию при первом запуске.

  • Бесплатные и платные версии с отдельными кодовыми базами и контроль источника. На первый взгляд это тоже кажется хорошей идеей, так как достойная система управления исходным кодом может снять вес с ваших плеч, но...

    Плюсы: то же самое, что и 3.
    Минусы: вы будете поддерживать две разные кодовые базы и ничего, кроме слияния/ветвления, которые можно ожидать здесь. Названия пакетов приложений должны быть разными, поэтому вам, вероятно, придется различать каждый отдельный файл, чтобы сохранить чистоту. И, конечно же, вам нужно будет предоставить своим пользователям удобный способ перенести свои предпочтения в платную версию при первом запуске.

  • Бесплатные и платные версии с script, которые производят один от другого. Это звучит как грязный хак, но вы точно знаете, что он работает.

    Плюсы: то же самое, что и 3 плюс вы поддерживаете только одну кодовую базу.
    Против: для создания сценариев требуется немного времени (убедитесь, что вы переименовываете папки, заменяете имена пакетов, приложений и проектов), и вы должны быть осторожны, чтобы время от времени обновлять свои сценарии, если необходимо (это не произойдет, если между свободной и платной версиями нет слишком много различий). И, конечно же, вам нужно будет предоставить своим пользователям удобный способ перенести свои предпочтения в платную версию при первом запуске.

Никакое решение не является совершенным, но выше, можно надеяться, укажет вам в правильном направлении, если вы собираетесь начать реализацию одной из возможностей.

Ответ 3

С системой сборки Gradle вы можете иметь разные вкусы продукта, каждый из которых имеет собственное имя пакета. Ниже приведен пример Gradle script, имеющий бесплатные и прообразные приложения того же приложения.

apply plugin: 'com.android.application'

android {
    compileSdkVersion 19
    buildToolsVersion "19.1"

    defaultConfig {
        applicationId "com.example.my.app"
    }

    productFlavors {
        free {
            applicationId "com.example.my.app"
            minSdkVersion 15
            targetSdkVersion 23
            versionCode 12
            versionName '12'
        }
        pro {
            applicationId "com.example.my.app.pro"
            minSdkVersion 15
            targetSdkVersion 23
            versionCode 4
            versionName '4'
        }
    }

R класс будет по-прежнему генерироваться в имени пакета, указанном в AndroidManifest.xml, поэтому вам не нужно менять одну строку кода при переключении ароматов.

Вы можете переключить аромат с панели Build Variants, доступной в левом нижнем углу Android Studio. Кроме того, если вы хотите создать подписанный APK, студия Android спросит вас, какой вкус вы хотите построить APK.

Кроме того, у вас могут быть разные ресурсы для каждого аромата. Например, вы можете создать каталог pro в каталоге src. Структура каталогов должна быть похожа на каталог main. (Например: если вы хотите иметь другой значок запуска для про версии, вы можете поместить его в src\pro\res\drawable. Это заменит свободный значок, расположенный в src\main\res\drawable, когда вы переключились на pro).

Если вы создадите каталог ресурсов strings.xml in pro, описанный выше, основные strings.xml и pro strings.xml будут объединены, чтобы получить окончательный strings.xml при построении в pro. Если существует определенный строковый ключ как в свободном, так и в pro xml, строковое значение будет взято из pro xml.

Если вам нужно проверить, является ли текущая версия про или бесплатной в коде, вы можете использовать метод, например следующий.

public boolean isPro() {
    return context.getPackageName().equals("com.example.my.app.pro");
}

Для получения дополнительной информации см. this

Ответ 4

Один исходный код для двух приложений (Eclipse)

Существует нерегулярная проблема управления приложением с двумя формами презентации на рынке, возможно, только с одной разницей в бит между ними (paidFor = true;) Возможно, иконка тоже отличается.

В этом подходе используется описание имен пакетов, объясненных Mihai в http://blog.javia.org/android-package-name/, что подчеркивает различие между именем пакета, используемым для управления источником код и имя пакета, используемого для публикации apk на Android Market. В этом примере двумя опубликованными именами пакетов являются com.acme.superprogram и com.acme.superprogrampaid, имя исходного кода Java-кода - com.acme.superprogram.

В манифесте действия перечислены и названы как .ActivityName. Майк Уоллес отметил в своей недавней презентации, что предыдущая точка важна, и ее можно заменить полностью квалифицированным пакетом. Например, "com.acme.superprogram.DialogManager" может заменить ".DialogManager" в тексте manifest.xml.

Шаг 1 заключается в том, чтобы заменить все записи андроида: имена этими полными именами пакетов, используя имя пакета управления исходным кодом java (com.acme.superprogram).

Затем можно изменить имя пакета манифеста...

В Eclipse это заставляет перекомпилировать, и в папке gen создается новый R.java. Здесь он становится немного сложнее; есть две папки com.acme.superprogram и com.acme.superprogrampaid, только у одного есть R.java. Просто скопируйте R.java в другую папку, чтобы программа могла разрешить элементы R.layout.xyz.

Когда вы меняете пакет в

Я попробовал это в нескольких приложениях. Я работаю вместе на эмуляторе, моем телефоне 2.1, и они оба находятся на Android Market.

Ответ 5

У меня была та же проблема, что я решил сделать, это два приложения для Android, одно из которых называется my_epic_app_free, а другое my_epic_app_paid. Я бы сделал только изменения в платной версии, тогда у меня есть отдельная консольная консольная программа, все, что она делает, - это доступ ко всем файлам .java непосредственно с диска, копирование их в память, скрипка с именами пакетов и строк манифеста, затем вставьте их прямо в бесплатное приложение. У меня есть это нажатие кнопки на рабочем столе, поэтому, когда я закончил разработку на платной версии, я нажимаю кнопку, а затем компилирую бесплатную версию. У меня есть как платное приложение, так и бесплатное приложение для общения друг с другом, пользователь может установить оба из них, а бесплатная версия видит платные и разблокируется в платной версии.

Еще одна идея - сделать платное приложение просто голой кодовой программой, содержащей ключевой файл. Платное приложение, если оно запускается, автоматически запускает бесплатную версию, а бесплатная версия будет вести себя как платная версия.

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

Пособие: никакие пользовательские данные/настройки не теряются при "обновлении" до платной версии.

Недостаток: если пользователь сначала устанавливает платную версию, им необходимо будет установить бесплатную версию, которая является проблемой, почему они должны установить два приложения для платной версии?

Ответ 6

На всякий случай, если у вас есть также модуль износа, необходимо выполнить дополнительную работу.

Вот несколько примеров Gradle файлов для упаковки модуля износа с ароматами и типами конструкций.

Модуль mobile build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "com.example.app"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 85
        versionName "2.5.2"
    }
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
            embedMicroApp = true
            minifyEnabled false
        }
        release {
            embedMicroApp = true
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            zipAlignEnabled true
        }
    }
    productFlavors {
        free{
            applicationId "com.example.app"
        }
        pro{
            applicationId "com.example.app.pro"
        }
    }
}

configurations {
    freeDebugWearApp
    proDebugWearApp
    freeReleaseWearApp
    proReleaseWearApp
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.4.0'

    freeDebugWearApp project(path: ':wear', configuration: 'freeDebug')
    proDebugWearApp project(path: ':wear', configuration: 'proDebug')

    freeReleaseWearApp project(path: ':wear', configuration: 'freeRelease')
    proReleaseWearApp project(path: ':wear', configuration: 'proRelease')
}

Износ модуля build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"
    publishNonDefault true

    defaultConfig {
        applicationId "com.example.app"
        minSdkVersion 20
        targetSdkVersion 23
        versionCode 85
        versionName "2.5.2"
    }
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
            minifyEnabled false
        }
        release {
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            zipAlignEnabled true
        }
    }
    productFlavors {
        free {
            applicationId "com.example.app"
        }
        pro {
            applicationId "com.example.app.pro"
        }
    }
}

dependencies {

    ...

}

Ответ 7

Если вы не хотите использовать проекты библиотек и довольны рисками, о которых несколько человек отметили в комментариях, то @user426990 предоставил отличный ответ теоретически. Тем не менее, eclipse, по-видимому, уничтожает все содержимое каталога gen при выполнении новой сборки для экспорта (с которой мне сложно спорить с общим принципом).

Альтернативное решение, основанное на том же принципе, заключается в следующем: предполагается, что вы написали com.acme.superprogram, и вы хотите создать com.acme.superprogrampaid

  • Убедитесь, что ваш манифест указывает на действия, службы и т.д. по имени. Согласно @user426990 ответ ".CoolActivity" должен быть указан как com.acme.superprogram.CoolActivity

  • Создайте новый класс MyR в коде (com.activity.superprogram, с остальной частью кода) следующим образом:

    package com.acme.superprogram;
    import com.acme.superprogram.R;
    
    public final class MyR {
        public final static R.attr     attr     = new R.attr();
        public final static R.color    color    = new R.color();
        public final static R.dimen    dimen    = new R.dimen();
        public final static R.layout   layout   = new R.layout();
        public final static R.id       id       = new R.id();
        public final static R.string   string   = new R.string();
        public final static R.drawable drawable = new R.drawable();
        public final static R.raw      raw      = new R.raw();
        public final static R.style    style    = new R.style();
        public final static R.xml      xml      = new R.xml();
    }
    

    Вам нужно будет изменить точный контент, чтобы отразить ресурсы, которые вы используете! Например, вам может не понадобиться строка xml и может потребоваться другая. Посмотрите на настоящий файл R.java в gen/com/acme/superprogram, и вам понадобится одна строка для каждого класса. Возможно, вам потребуется подкласс.

  • Теперь (а) удалите все строки "import com.acme.superprogram.R" из вашего кода и (b) замените все "R." ссылки на "MyR". Таким образом, все ваши ссылки на R косвенно связаны через одно место. Недостатком является то, что все они получают предупреждения о том, что они недостаточно статичны. У вас есть три варианта с этими предупреждениями: вы можете их подавить, вы можете их игнорировать, или вы можете сделать более полную версию MyR с линией для каждой записи в R, которую вы используете:

    package com.acme.superprogram;
    import com.acme.superprogram.R;
    
    public final class MyR {
        final static class attr {
            final static int XXXX = R.attr.XXXX
    // And so on ...
    
  • В соответствии с @user426990 теперь вы можете изменить пакет в манифесте с "com.acme.superprogram" на "com.acme.superprogrampaid"; вы, вероятно, также захотите изменить имя, значок запуска и ключевые переменные на этом этапе.

  • Измените строку импорта в MyR для импорта com.acme.superprogrampaid.R

И уходите.

пс. Не забудьте изменить имя файла в окне окончательного экспорта...

Ответ 8

Изменение имени пакета поможет.
 Просто измените имя пакета вашего платного приложения с помощью eclipse и поставьте его на рынок.

Это решит вашу проблему.

Ответ 9

Почему бы не создать два разных проекта Eclipse? Не так сложно исправить несколько вещей, относящихся к имени пакета вручную. Позаботьтесь об изменении операторов импорта и файла манифеста. В любом случае вам нужно дважды закодировать код. Конечно, неудобно исправлять код в обоих местах.

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

Рене