Writing your Android Market

As part of the work on a large number of android applications, there was a desire to create your Android Market on a local server (with chess and poetesses).
Your market should solve two simple problems:
  • Distribution and updating of corporate applications. We have a set of corporate applications that cannot be published on Google Play. Now users are notified of new versions by email, which is not convenient.
  • Beta testing of custom applications on a large group of colleagues, with feedback.


And so, we need to implement a small Android application that will download a list of available applications, check for updates for existing ones, install / uninstall applications.

Server side


The server part of the application can be either a service with wide functionality (user registration, reports, access control for applications), or just an xml file:

.....

In my case, the server part is actually the http ball.
This xml file in the application is transformed into a list of applications available for installation.

Installation


The user selects the application he needs and installs,
Market downloads the apk file to the device’s flash drive and initiates the installation of the application, of course, installation from third-party sources should be allowed.
We cannot install quietly in the background, therefore, after executing this code:
			URL url = new URL(apkurl);
			HttpURLConnection c = (HttpURLConnection) url.openConnecвленtion();
			c.setRequestMethod("GET");
			c.setDoOutput(true);
			c.connect();
			File file = this.getExternalFilesDir("download");
			File outputFile = new File(file, "app.apk");
			FileOutputStream fos = new FileOutputStream(outputFile);
			InputStream is = c.getInputStream();
			byte[] buffer = new byte[1024];
			int len1 = 0;
			while ((len1 = is.read(buffer)) != -1) {
				fos.write(buffer, 0, len1);
			}
			fos.close();
			is.close();
			Intent intent = new Intent(Intent.ACTION_VIEW);
			intent.setDataAndType(Uri.fromFile(outputFile),
					"application/vnd.android.package-archive");
			startActivity(intent);

The user will see a standard application installation window:
image

Update


The Market application can check for new versions at a certain interval, this is done quite simply, since a list of all installed applications is available:
	private boolean checkNewVersion(String packageName, int versionCodeNew) {
		List apps = getPackageManager()
				.getInstalledApplications(0);
		for (int i = 0; i < apps.size(); i++) {
			ApplicationInfo app = apps.get(i);
			if (packageName.equals(app.packageName)) {
				PackageManager manager = getPackageManager();
				PackageInfo info;
				try {
					info = manager.getPackageInfo(app.packageName, 0);
					int versionCode = info.versionCode;
					if (versionCodeNew > versionCode) {
						Toast.makeText(this, "New Version!", Toast.LENGTH_LONG)
								.show();
						return true;
					}
				} catch (NameNotFoundException e) {
					e.printStackTrace();
				}
			}
		}
		return false;
	}

If it is necessary to update the application, repeat the Installation process, the application will be updated.

Delete


It is better to remove the program from the interface of our market in order not to force the user to search for the tested application among all its programs, for this it is enough to call this code:
		Uri packageURI = Uri.parse("package:"+packageName);
		Intent intent = new Intent(Intent.ACTION_DELETE, packageURI);
		startActivity(intent);

image

Feedback


Receiving error messages, along with the error log, is very important for the developer, especially at the application testing stage, we will add the function of automatically collecting this information through the Market.

To do this, in each application distributed through our Market add the following class
public class CustomExceptionHandler implements UncaughtExceptionHandler {
	private File logsFolder = null;
    public static final String ERROR_INTENT = "com.example.markettestapp1.SEND_ERROR";
	public CustomExceptionHandler(File logsFolder) {
		this.logsFolder = logsFolder;
	}
	@Override
	public void uncaughtException(Thread thread, Throwable ex) {
	    final Writer result = new StringWriter();
	    final PrintWriter printWriter = new PrintWriter(result);
	    ex.printStackTrace(printWriter);
	    String stacktrace = result.toString();
	    printWriter.close();
		try {
			if (!logsFolder.exists()) {
				logsFolder.createNewFile();
			}
			BufferedWriter writer = new BufferedWriter(new FileWriter(logsFolder, true));
			writer.write(""+new Date()+"\n"+stacktrace);
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		Intent intent = new Intent();
		intent.setAction(ERROR_INTENT);
		intent.putExtra("packageName", Test1Application.getApplication().getPackageName());
		intent.putExtra("stacktrace", stacktrace);
		Test1Application.getInstanceApplication().sendBroadcast(intent);
		android.os.Process.killProcess(android.os.Process.myPid());
	}
}

As you can see from the code, this is a handler that receives errors (Exception), generates a line with a stack, saves it to a local file and sends an error in the form of a broadcast message.

And in the Application class, we enable the forwarding of all error messages to this handler
public class Test1Application extends Application {
	@Override
	public void onCreate() {
		super.onCreate();
		application = this;
		Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(new File(this.getApplicationContext().getExternalFilesDir(null),"exceptions.log")));
	}

Thus, if an error occurs in the test application, then before death a message is written to the log and a broadcast message is sent to the market.
Before sending the application to the customer, this code is deleted (commented out).

In the Market itself, we simply catch this message:
public class SendErrorReceiver  extends BroadcastReceiver {
    public static final String ERROR_INTENT = "com.example.markettestapp1.SEND_ERROR";
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent i = new Intent(context, SendErrorActivity.class);
        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        i.putExtra("stacktrace", intent.getStringExtra("stacktrace"));
        i.putExtra("packageName", intent.getStringExtra("packageName"));
        context.startActivity(i);
    }
}

AndroidManifest.xml:


And then the market can already send this message to the developer’s mail, upload it to some kind of web service or ask the user to add a comment to the error.
image

I hope this example will help many novice developers to figure out how to write their universal bike for beta testing applications and centralized collection error statistics.

ps: The article uses the source code and pictures taken from the prototype application.

Also popular now: