问题描述
最近,我将在一个项目上工作,其中要求很奇怪.我被要求开发一个应用程序,该应用程序将不会上传到PlayStore或任何其他Android应用商店等任何市场.它将只是在云中上传以分发用户之间的APK.
在应用程序上安装在用户设备上后,将释放新版本时,将通知用户(通知NOT下载新版本并重新安装,但要授予权限和更新).用户授予权限后,将更新该应用程序.没有市场帮助的情况下做到这一点的最佳方式是什么?
我的想法:
- 使用GCM(Google Cloud Messaging)通知用户并提供新的版本链接.
- 用户将单击链接,将下载新版本并更换前一个(Android返回版本替换)
是有没有更聪明的方式来做我想要实现的事情?
推荐答案
我发现的最佳方法是托管apk和最新版本#的文本文件.
opon打开应用程序,检查当前v#对阵服务器上托管的那个,如果它们不匹配,请抓住新的.
除非您的应用程序作为后台服务,否则无需推动任何内容,并且您需要确保用户是否在最新版本中使用它.
如果是这样的话,您可以使用一天或类似的东西.
编辑 - 下载后,要安装APK,请使用以下代码.
Intent promptInstall = new Intent(Intent.ACTION_VIEW) .setDataAndType(Uri.parse("file:///path/to/your.apk"), "application/vnd.android.package-archive"); startActivity(promptInstall);上编程安装应用程序
其他推荐答案
这是我为此目的使用的一些代码.你将不得不调整一些,因为我懒得把它脱落atm. (对不起).
所以,在我的活动中我有:
new FetchLatestVersion().execute();
和要检查的代码和获取最新版本(+启动安装程序).
private class FetchLatestVersion extends AsyncTask<Void, Void, Integer> { @Override protected Integer doInBackground(Void... param) { String inputLine = "-1"; BufferedReader in = null; try { URL update_url = new URL(UPDATE_VERSIONCHECK_URL); in = new BufferedReader(new InputStreamReader( update_url.openStream())); while ((inputLine = in.readLine()) != null) { return Integer.parseInt(inputLine); } } catch (IOException e) { Log.e(TAG, inputLine, e); } catch (NumberFormatException e) { Log.e(TAG, inputLine, e); } finally { try { if (in != null) { in.close(); } } catch (IOException e) { } } return -1; } @Override protected void onPostExecute(Integer result) { if (result > device.getVersionCode()) { // Toast.makeText( // getApplicationContext(), // "current version: " + device.getVersionCode() + "\n" // + "new version: " + result, Toast.LENGTH_SHORT) // .show(); // pref.putBoolean(PREF_HAS_UPDATE, true); showDownloadOption(); } } } private void showDownloadOption() { findViewById(R.id.new_update).setVisibility(View.VISIBLE); } @OnClick(R.id.button_download) public void update(Button button) { if (mDownloadTask != null && mDownloadTask.getStatus() == Status.RUNNING) { mDownloadTask.cancel(true); } mDownloadTask = new DownloadUpdate(); mDownloadTask.execute(); } private class DownloadUpdate extends AsyncTask<Void, Void, File> { public ProgressDialog working_dialog; private String toastMsg = ""; @Override protected void onPreExecute() { working_dialog = ProgressDialog.show(context, "", context.getString(R.string.working), true); } @Override protected File doInBackground(Void... param) { String filename = "YOURAPP.apk"; HttpURLConnection c = null; try { URL url = new URL(UPDATE_DOWNLOAD_URL); c = (HttpURLConnection) url.openConnection(); c.setRequestMethod("GET"); c.setDoOutput(true); c.connect(); } catch (IOException e1) { toastMsg = context .getString(R.string.could_not_connect_to_server); return null; } File myFilesDir = new File(Environment .getExternalStorageDirectory().getAbsolutePath() + "/Download"); File file = new File(myFilesDir, filename); if (file.exists()) { file.delete(); } if ((myFilesDir.mkdirs() || myFilesDir.isDirectory())) { try { InputStream is = c.getInputStream(); FileOutputStream fos = new FileOutputStream(myFilesDir + "/" + filename); byte[] buffer = new byte[1024]; int len1 = 0; while ((len1 = is.read(buffer)) != -1) { fos.write(buffer, 0, len1); } fos.close(); is.close(); } catch (Exception e) { toastMsg = context .getString(R.string.missing_internet_connection); } } return file; } @Override protected void onPostExecute(File file) { if (!toastMsg.isEmpty()) { Toast.makeText(context, toastMsg, Toast.LENGTH_LONG).show(); } else { launchInstaller(file); } removeWorkingDialog(); } private void removeWorkingDialog() { if (working_dialog != null && working_dialog.isShowing()) { working_dialog.dismiss(); working_dialog = null; } } } public void launchInstaller(File apkFile) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivityForResult(intent, 0); }
其他推荐答案
我做了少量的挖掘,发现了一个完全正确的库. 我没有用它,但它在其他相关的其他相关问题中突然出现.
问题描述
Recently I am going to work on a project in which the requirement is little weird. I am asked to develop a app which will not be uploaded to any marketplace like playstore or any other android app stores. It will be simply uploaded in cloud to distribute the APK among users.
After the app is being installed on user device, when a new version will be released, the user will be notified (notified not to download the new version and re-install, but to grant permission and update). After the user grant permission, the app will be updated. What's the best way to do this without the marketplace help?
My idea:
- Use GCM (Google Cloud Messaging) to notify user and give a new version link.
- User will click on the link and a new version will be downloaded and replaced the previous one (android by-default version replacement)
Is there any smarter way to do what I want to achieve actually?
推荐答案
The best way to do this I have found, was to host the apk and a text file with the latest version #.
Opon opening the app, check the current v # against the one hosted on the server, if they dont match, grab the new one.
No need for pushing anything unless your app works as a background service and you need to ensure that whether the user is on the latest version whether they use it or not.
If that is the case, you can have a service that does it once a day or something like that.
EDIT - after downloaded, to install the apk, use the following code.
Intent promptInstall = new Intent(Intent.ACTION_VIEW) .setDataAndType(Uri.parse("file:///path/to/your.apk"), "application/vnd.android.package-archive"); startActivity(promptInstall);
Install Application programmatically on Android
其他推荐答案
Here is some of the code I use for this purpose. You will have to adjust some as I am too lazy to strip it down atm. (sorry).
So, in onCreate of my Activity I have:
new FetchLatestVersion().execute();
And the code to check for and fetch latest version (+launch installer).
private class FetchLatestVersion extends AsyncTask<Void, Void, Integer> { @Override protected Integer doInBackground(Void... param) { String inputLine = "-1"; BufferedReader in = null; try { URL update_url = new URL(UPDATE_VERSIONCHECK_URL); in = new BufferedReader(new InputStreamReader( update_url.openStream())); while ((inputLine = in.readLine()) != null) { return Integer.parseInt(inputLine); } } catch (IOException e) { Log.e(TAG, inputLine, e); } catch (NumberFormatException e) { Log.e(TAG, inputLine, e); } finally { try { if (in != null) { in.close(); } } catch (IOException e) { } } return -1; } @Override protected void onPostExecute(Integer result) { if (result > device.getVersionCode()) { // Toast.makeText( // getApplicationContext(), // "current version: " + device.getVersionCode() + "\n" // + "new version: " + result, Toast.LENGTH_SHORT) // .show(); // pref.putBoolean(PREF_HAS_UPDATE, true); showDownloadOption(); } } } private void showDownloadOption() { findViewById(R.id.new_update).setVisibility(View.VISIBLE); } @OnClick(R.id.button_download) public void update(Button button) { if (mDownloadTask != null && mDownloadTask.getStatus() == Status.RUNNING) { mDownloadTask.cancel(true); } mDownloadTask = new DownloadUpdate(); mDownloadTask.execute(); } private class DownloadUpdate extends AsyncTask<Void, Void, File> { public ProgressDialog working_dialog; private String toastMsg = ""; @Override protected void onPreExecute() { working_dialog = ProgressDialog.show(context, "", context.getString(R.string.working), true); } @Override protected File doInBackground(Void... param) { String filename = "YOURAPP.apk"; HttpURLConnection c = null; try { URL url = new URL(UPDATE_DOWNLOAD_URL); c = (HttpURLConnection) url.openConnection(); c.setRequestMethod("GET"); c.setDoOutput(true); c.connect(); } catch (IOException e1) { toastMsg = context .getString(R.string.could_not_connect_to_server); return null; } File myFilesDir = new File(Environment .getExternalStorageDirectory().getAbsolutePath() + "/Download"); File file = new File(myFilesDir, filename); if (file.exists()) { file.delete(); } if ((myFilesDir.mkdirs() || myFilesDir.isDirectory())) { try { InputStream is = c.getInputStream(); FileOutputStream fos = new FileOutputStream(myFilesDir + "/" + filename); byte[] buffer = new byte[1024]; int len1 = 0; while ((len1 = is.read(buffer)) != -1) { fos.write(buffer, 0, len1); } fos.close(); is.close(); } catch (Exception e) { toastMsg = context .getString(R.string.missing_internet_connection); } } return file; } @Override protected void onPostExecute(File file) { if (!toastMsg.isEmpty()) { Toast.makeText(context, toastMsg, Toast.LENGTH_LONG).show(); } else { launchInstaller(file); } removeWorkingDialog(); } private void removeWorkingDialog() { if (working_dialog != null && working_dialog.isShowing()) { working_dialog.dismiss(); working_dialog = null; } } } public void launchInstaller(File apkFile) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivityForResult(intent, 0); }
其他推荐答案
I did a small amount of digging and found a library that does exactly this. I have not used it, but it popped up in some other related SO questions.