I worked on a similar problem recently.
The best solution for my use case was:
1) Establish a unique id for each and every device that has the app installed.
2) Do not allow the app to run until the online database has been connected to.
Once connected to the online database check to see if that unique id has already been added to the database.
If the unique id already exists then has that device's trial period ended or not - allow the app to run accordingly.
If the unique id does not exist in the database then grant the user a trial period.
This ensures that the user cannot simply uninstall and then reinstall the app.
3) Assuming that the app is now running in trial or paid for mode, each time the app is started a connection to the database is made and the app's status checked.
If no internet connection is available the app will continue to run - unless the trial period (as stored on the device) has come to an end.
Now this app uses the internet and is in fact pretty useless with no internet connection.
So if the user disables internet to enable the app to continue to run then the app will have no practical use.
4) If the app is started and an internet connection is available then the app's status is checked.
The details stored on the device are also compared to the details stored in the online database - any attempt by the user to hack the details stored on the device will be detected and the app no longer work.
Lastly, using the read and write encryted objects methods of the
RandomAccessFile library to store details about the app's status makes it pretty difficult for the average user to hack the stored details to extend the trial period.
Martin.