【问题标题】:Maintaining both free and pro versions of an application维护应用程序的免费版和专业版
【发布时间】:2010-03-27 11:20:29
【问题描述】:

我想为我的 Android 应用程序创建一个 PRO 版本,并且想知道如何构建我的存储库。

要知道我有一个主干和功能分支。我想将专业版放在另一个分支中,但也许有更好的方法?例如,也许我应该创建两个分支 - 一个是免费版,另一个是专业版?

专业版将具有附加功能并且无广告,例如。我不想在专业版中包含 AdMob 库。

对于在这种情况下构建存储库的最佳方式,您有任何经验或建议吗?

编辑: 我想我在这个线程中找到了最好的解决方案(对于我的应用程序):http://groups.google.com/group/android-developers/browse_thread/thread/4ad3d67f735f16d7/948b4f9eee2490a3

这里讨论的技巧是关于拥有另一个仅用于在实际应用程序中解锁 PRO 功能的应用程序。解锁应用是在市场上付费的,实际应用只是检查设备上是否存在。

【问题讨论】:

  • 如果用户只安装付费的“解锁”应用程序并期望它会起作用怎么办?用户不会感到困惑吗?

标签: android versioning maintainability


【解决方案1】:

我知道您已经做出了决定,但我还有另一个建议可能对其他人有所帮助。

我使用 git 作为我的存储库。创建和维护分支非常容易。我有我的主“专业”存储库和一个“免费”分支。我对主人进行了所有代码更改。我的“免费”分支仅因触发“免费”行为的任何更改而有所不同。 每当我完成对代码的更改时,我都会将其提交到 master 分支,然后切换到 free 分支并使用“rebase”命令将其赶上 master。

它回滚使其表现为“免费”版本的更改,应用我对 master 所做的更改,然后重新应用“免费”更改。

我不必维护两个版本。我不必记得切换某个开关,或者来回进行相同的更改。它非常漂亮,我比触发专业行为的第二个应用程序更喜欢它,因为我可以删除相关版本不需要的库。

【讨论】:

  • 我自己没想到这一点(我是 Subversion 用户,现在开始在 svn repos 上使用 git)。感谢您的提示,我将自己尝试一下(尽管我可能必须制作一个真正的 git repo 服务器(我想要那些备份)...)
  • 非常有趣。我会调查一下。谢谢。
  • 我对 It rolls back ... 段落感到困惑,这是由 rebase 完成的吗?还是你必须这样做?
  • 这一切都是变基的一部分。
  • 虽然这种方法对于单人开发团队可能是可行的,但它不适用于共享存储库。重复的变基更改历史记录,因此您必须强制推送到共享存储库并确保共享存储库的所有克隆都遵循,这实际上几乎是不可能的。
【解决方案2】:

我建议不要维护两个分支,而是使用运行时或编译时开关来禁用免费版本的 PRO 功能。您甚至可以在构建时删除不需要的 DLL。

维护两个分支意味着在两个地方解决问题,随着分支不可避免地分叉,这将成为更大的问题。

【讨论】:

  • 看起来很合理。我还发现了一个建议,即提供一个付费的“解锁”应用程序,如果想要使用专业功能,只需将其安装在设备上即可。
  • 请分享有关“解锁”应用的信息 :)
  • @Immortal 这就是 Touiteur 所做的,虽然我不知道它是如何实现的,但它简单且不引人注目。
  • 它对您来说最简单,对任何希望升级的客户来说都是最方便的。
  • @illojal 我已更新问题以包含有关“解锁应用程序”方法的信息。
【解决方案3】:

我在 Eclipse 中找到了一种简单的方法。当我发现它时,我对它的简单程度感到非常惊讶。

  1. 在 com.app.free 的项目属性中,检查“Is Library”是否为真(在更改此选项之前,您必须至少编译过一次项目,否则您会收到错误消息,指出无法编译库项目,如果您确实得到了这个错误只需取消检查,编译,然后重新检查。
  2. 创建新项目 com.app.pro
  3. 在项目的android部分的项目设置中将com.app.free项目添加为库
  4. 在 com.app.pro 中创建新类 MyApplication 并扩展 Application
  5. 覆盖 onCreate() 注意:对于那些复制/粘贴的伙伴,这与活动的 onCreate(Bundle savedInstanceState) 包不同。您必须删除 Bundle 参数,因为这是一个应用程序而不是一个活动。
  6. 然后添加或设置将在验证方法中读取的静态变量以验证许可证。例如:IS_PRO = 真;然后验证方法读取变量并在 IS_PRO 为真时返回真。
  7. 将清单内容从 com.app.free 复制到 com.app.pro
  8. 将 android:name="MyApplication" 添加到 com.app.pro 清单中的应用程序标签
  9. 在所有活动的名称属性前附加 com.app.free。 (这使应用程序知道您的活动可以在免费版本的库包中找到)EX:android:name=".MainActivity" => android:name="com.app.free.MainActivity"李>
  10. 现在编译,你就有了专业版

此方法假定您使用的是全局验证方法。例如,我创建了一个类,将用户连接到托管在我的域上的数据库,该数据库确定用户首次安装应用程序的时间。对于任何仅限专业人士的活动,我会检查 LicenseClass.isValidLicense(),它比较日期并在小于所需天数时返回 true。在 isValidLicense() 函数中,我检查 Application.IS_PRO 是否设置为 true,如果是则返回 true。

因此,现在您可以进行尽可能多的更改,无论多么频繁,您所要做的就是重新编译两者。唯一要记住的是,您在 com.app.free 清单中所做的任何更改都必须反映在 pro 中。但任何应用程序都是如此,因为 android 应用程序要求您声明无论如何要使用哪些活动。

注意:您可以删除在项目创建时自动生成的所有资产和资源(但不要删除 res 文件夹本身),因为它们不会被使用。此外,唯一需要的类文件是步骤 3 中的 MyApplication 文件。这意味着您也可以删除自动生成的 MainActivity.class,因为它也从未使用过。您还可以删除专业版中未使用的任何标签。 EX:我有一个 BuyPro 活动,如果验证失败,它会打开。由于验证在专业版中永远不会失败,因此不需要。当然,所有这些删除都是可选的,只是让您知道我学到了什么。

缺点:到目前为止,我发现的唯一缺点是您不能对资源变量使用 switch 语句,因为它们不再是常量。因此,当您将项目用作库时,例如,如果您在专业版中声明了同名的变量,您在 strings.xml 文件中创建的任何变量都会自动覆盖。对我来说这不是一个缺点,因为我不喜欢在 java 中使用 switch 状态,因为它们限制你只能打开 int 类型并且它们需要常量值。这意味着在 java 中我通常需要我们 if ... else 语句。另外,如果您将光标放在 switch 关键字上并按 Ctrl+1 然后单击 convert to if else,Eclipse 实际上会帮助转换 switch 语句。此外,我发现覆盖资源非常有用,因为您可以执行诸如将 app_name 从“app free”更改为“app pro”之类的操作,或者只需通过在它存在于免费应用程序中。 EX:如果 res/values/string.xml 包含 100 个字符串变量,但您需要或想要在专业版中更改的只是 app_name,只需重新创建 res/values/string.xml(不复制)并添加 app_name 变量.现在免费版中的 app_name 变量将被覆盖,这意味着专业版中的 string.xml 文件只需要包含 1 变量而不是 100,因为它是唯一更改的变量。十分简单。 :-)

编辑:我发现 Eclipse 不允许您为库导出 .apk,因此在将免费版本中的“Is Library”选项添加为专业版后,您必须取消选中“Is Library”选项。据我所知,这样做的唯一一件事就是导致 eclipse 不会警告您有关 switch 语句的问题。除此之外,它似乎工作得很好。

【讨论】:

  • 这个答案需要更多的爱。 +1
【解决方案4】:

拥有一个带有public static final boolean IS_PRO 的版本,这将决定免费/专业的行为。

编辑:
包的东西。比如说,你所有的课程都在com.myapp.android.free下。
然后,在 AndroidManifest.xml 中声明 package="com.myapp.android" 为付费版本,package="com.myapp.android.free" 为免费版本。
如果您对活动、服务等使用全名,则无需更改任何其他内容。

我不会费心从付费版本中删除未使用的库。如果这样做,则必须手动执行此操作。

【讨论】:

  • 是的,好像我没想到那样:/ 在 Android Market 上发布应用程序怎么样?包必须是唯一的。在专业版中不包含 AdMob jar 怎么办?
  • 感谢您的回答。我想我会采用“解锁应用程序”的方法。
  • 问题是包名不仅用在清单中,而且还用在你所有引用 R.java 类(通常是很多类)的java代码上。
  • 如何为 .xml 文件执行此操作?
猜你喜欢
  • 2011-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-12
  • 1970-01-01
  • 2015-10-01
相关资源
最近更新 更多