Android Tutorial Trial Tutorial

Hey everyone,

Here I will explain how you can make an evaluation/trial version of your app using an online database.
With this, the user will be able to open up the app x times. When 0 is achieved, it will force close the app.

First you'd need some basic knowledge of HTML, PHP, SQL and ofcourse Basic4Android.
I will not explain on how to setup your directory files, SQL Database, etc.

Here's how it works:

Before the app runs (in globals) I send my IMEI with a POST Method to a php webserver. I do this with one code with a library I have written, instead of using HTTPUtils etc.
The database exists of three columns:
id, IMEI, starts.

The PHP file looks in the database if the IMEI exists, if it exists, it looks for the amount in the third column and substracts 1. If it doesn't exists, a IMEI.txt file is generated. The file contains how much the app can be opened. 30 here.
If 0 is succeeded, the text Expired appears.

In my app, a timer runs during 6 seconds. This is done to process everything server side. When the timer ticks, I perform a http GET to the IMEI.txt (its not IMEI.txt but e.g. 59644885484.txt). If the response string is an amount, then the app runs, otherwise if it's "Expired", then the app is closed.

Some code:

B4X:
Sub Globals
        ProgressDialogShow("Trial Activated" & CRLF & "Connecting with webserver for authentication")
   Dim p As PhoneId
   Dim cantopen As Boolean
   cantopen = False
   Dim camera1 As AdvancedCamera
   Dim strActivationCheck As String
   strActivationCheck = "http://www.example.com/" & p.GetDeviceId & ".txt"

'Small password protection, PHP File on webserver, IMEI, Trials
' change the url to the url of your site.
'You should download the latest version of my Advanced Camera Library to use 'AppTrial' because it is a lot easie for me this way instead of working with HTTPutlils.
   Camera1.AppTrial("Password","http://www.example.com/trialCheck.php",p.GetDeviceId,30)

   tmrEvaluation.Initialize("tmrEvaluation",6000)
   tmrEvaluation.Enabled = True

End Sub

Sub tmrEvaluation_tick
   ProgressDialogShow("Checking Activation.")
   tmrEvaluation.Enabled = False
   Dim request1 As HttpRequest
   request1.InitializeGet(strActivationCheck)
   request1.Timeout=50000
   If HttpClient1.Execute(request1, 1) = False Then
   Return
   End If
End Sub

Sub http_ResponseSuccess (Response As HttpResponse, TaskId As Int)
   ProgressDialogHide()
   If TaskId = 1 Then
   Dim strActivationResponse As String
   strActivationResponse = response.GetString("UTF8")
      If strActivationResponse = "Expired" Then
      cantopen = True
         Msgbox("The evaluation version of StreamNation Studio has expired." & CRLF & "You can buy the full version or take the chance of winning the full version by rating the app and giving it a small review!","Evaluation")
         ExitApplication
      Else
         Msgbox("You can run the app " & strActivationResponse & " more times.","Evaluation")
      End If
   End If

End Sub

Sub Http_ResponseError (Response As HttpResponse, Reason As String, StatusCode As Int, TaskId As Int)
    If TaskId = 1 Then
   Msgbox(Reason,"An error occured." & CRLF & "Check your internet connection or try again later.")
   ExitApplication
   End If

End Sub

Attached is the PHP file. Upload it and link to that PHP File.
It is commented. Open it and edit where asked.

Here is a maintenance table of how many times StreamNation Studio is downloaded, opened, used,...:

http://www.rootsoftllc.com/streamNation/trialStats.php

XverhelstX
 

Attachments

  • ServerPHP.zip
    739 bytes · Views: 734
Last edited:

Penko

Active Member
Licensed User
Longtime User
Hey, Timo.

There is actually nothing to free, maybe just mysql_close at the end but it's no so vital.

Also, check the UPDATE query, you have missed the "LIMIT 1".

What I would also suggest you, assign a default value of the result. E.g "CANT_CHECK_REMAINING_DAYS" and don't use die(). If for some reason the server can't connect to MySQL, what would your script return to the B4A client if there is no default value? You can experimentate yourself by changing your MySQL password parameter in mysql_connect(). This would die() the script at the first line and you will see what I am talking about.

Well, of course it depends on the client but I don't see this handled or at least not in the shown code snippet. Sorry if it is implemented and I haven't noticed it, I've just returned from a party at the neighbours's house.

If you haven't understood my currently bad English, here I explain in code:

B4X:
$result = "CANT_GET_DAYS"; // a default "CANT CONNECT VALUE"

mysql_connect($host, $user, $pass);
$result = $row['days']; // HERE THE VALUE WILL BE CHANGED IF THE DATABASE OPERATION IS SUCCESSFUL
 

timo

Active Member
Licensed User
Longtime User
I don't worry about what happend if a MySql connection doesn't work: b4a code (see)gives you a "try later"and does not decrement (try changing to a wrong pwd with your own server). A non json object is extremely difficult to become as response. Limit 1 I think is not 100% sure in this case, so I finally woul prefer not to put it there. Anyway, it is pratically impossible to have two records for the same imei, and if it happened by chance, Limit 1 will cause problems. The code is an example, not an application. You still have to manage a lot of things in real implementation on the b4a code.
 

Penko

Active Member
Licensed User
Longtime User
I was from my mobile and couldn't post the whole text I wanted.

If we assume IMEIs can be dublicated then the whole "remaining days concept" is probably wrong.

One user can have started the app just a few times and to get "EXPIRED" because the other user has gone over 30.

This is the right moment to ask if there is anything else as unique as IMEI to combine IMEI with and thus make dublications hardly possible?
 

Fox

Active Member
Licensed User
Longtime User
Hello guys!

Ok i have tried every example the 1 from XverhelstX hangs on the activation no response.

the 2. from timo on one of my webspace i get no sql response...

but another get me response but then it hangs on json command in b4a is there no phone solution just with text file or so?

I get this following error:

--------- beginning of /dev/log/system
--------- beginning of /dev/log/main
Installing file.
PackageAdded: package:t.t.c
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
main_httpc_responsesuccess (B4A line: 58)
m=JSON.NextObject
org.json.JSONException: Expected literal value at character 0 of ]

<!-- www.000webhost.com Analytics Code -->

<script type="text/javascript" src="http://analytics.hosting24.com/count.php"></script>

<noscript><a href="http://www.hosting24.com/"><img src="http://analytics.hosting24.com/count.php" alt="web hosting" /></a></noscript>

<!-- End Of Analytics Code -->

at org.json.JSONTokener.syntaxError(JSONTokener.java:446)
at org.json.JSONTokener.readLiteral(JSONTokener.java:281)
at org.json.JSONTokener.nextValue(JSONTokener.java:107)
at anywheresoftware.b4a.objects.collections.JSONParser.NextObject(JSONParser.java:45)
at t.t.c.main._httpc_responsesuccess(main.java:432)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:136)
at anywheresoftware.b4a.BA$2.run(BA.java:244)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:144)
at android.app.ActivityThread.main(ActivityThread.java:4937)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)
org.json.JSONException: Expected literal value at character 0 of ] <<< this must be the error

<!-- www.000webhost.com Analytics Code -->

<script type="text/javascript" src="http://analytics.hosting24.com/count.php"></script>

<noscript><a href="http://www.hosting24.com/"><img src="http://analytics.hosting24.com/count.php" alt="web hosting" /></a></noscript>

<!-- End Of Analytics Code -->

** Activity (main) Pause, UserClosed = false **

Any solution for me?
 
Last edited:

Fox

Active Member
Licensed User
Longtime User
if i started the file in the browser it works but on android not work...

here is the code:

Sub Process_Globals
Dim httpC As HttpClient
'put here to obfuscate user,password,php.name and hosting [->Release(obfuscated)]
Dim indirizzo As String : indirizzo= "xxxxxxxxxxxxxxxxxxxxxxxxxxx?imei="
'Dim parcheggio As String: parcheggio="http://www.yourSite.com/" '(no more needed here)
End Sub

Sub Globals
Dim p As PhoneId
Dim deviceID As String
deviceID = p.GetDeviceId
Dim m As Map

End Sub

Sub Activity_Create(FirstTime As Boolean)
If FirstTime Then
httpC.Initialize("httpC")
End If
checkTrialsRemaining

End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
Activity.Finish
End Sub

Sub checkTrialsRemaining
Dim req As HttpRequest
req.InitializeGet(indirizzo&deviceID)
httpC.Execute(req,1)
ProgressDialogShow("Validation ...")

End Sub


Sub httpC_ResponseSuccess (Response As HttpResponse, TaskId As Int)

Dim result As String
Dim JSON As JSONParser
Dim restOpen As Int

result = Response.GetString("UTF8")

'Optional: Remove '[' and ']' from the response received from my server:-> array[{jsonObject}]
Dim tmp As String
Dim lungh As Int
tmp=result
lungh= tmp.Length
tmp= tmp.SubString2(1,lungh-1) 'cut first+last char
result=tmp
'-----------------------------------------------------

JSON.Initialize(result)
Dim m As Map
m=JSON.NextObject <<< here the phone gets an error in debug mode...

restOpen=m.Get("startsleft")
ProgressDialogHide

If restOpen=0 Then
Msgbox("Trial expired"," Trial")
Response.Release
Activity.Finish
Else
If restOpen > 1 Then
Msgbox((restOpen - 1)&" out of 3 openings remaining"," Trial")
Else
Msgbox("Last opening of 3"," Trial")
End If
End If
Response.Release
End Sub

Sub httpC_ResponseError (Response As HttpResponse, Reason As String, StatusCode As Int, TaskId As Int)
'no Reason shown in order not to give the user informations about hosting and php names:
ProgressDialogHide
Msgbox("Connection error. Try later again."," Trial")

If Response <> Null Then
Log("Resp.not Null")
Response.Release
End If
'If no web connection is available, Response is naturally Null and you don't have to release a Null object
ExitApplication
End Sub

i just copy and past the code just for checking
 
Last edited:

timo

Active Member
Licensed User
Longtime User
m=JSON.NextObject <<< here the phone gets an error in debug mode...

I think it's a json format problem . When I wrote this code I adaptet it to treat it as object, but I think that the json response here begins with an array. But be careful of what i'm writing: Json it's not a thing I know welland that piece of code was really 'empiric'

P.S. can't succed in downloading from link
(you can post php and b4a code as Penko suggested)
 
Last edited:

Fox

Active Member
Licensed User
Longtime User
here is my Log

LogCat connected to: B4A-Bridge: HTC HTC Desire-355302044677731
--------- beginning of /dev/log/system
--------- beginning of /dev/log/main
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
main_httpc_responsesuccess (java line: 324)
org.json.JSONException: End of input at character 0 of
at org.json.JSONTokener.syntaxError(JSONTokener.java:446)
at org.json.JSONTokener.nextValue(JSONTokener.java:93)
at anywheresoftware.b4a.objects.collections.JSONParser.NextObject(JSONParser.java:45)
at t.t.c.main._httpc_responsesuccess(main.java:324)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:136)
at anywheresoftware.b4a.BA$2.run(BA.java:244)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:144)
at android.app.ActivityThread.main(ActivityThread.java:4937)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)
org.json.JSONException: End of input at character 0 of
Installing file.
PackageAdded: package:t.t.c
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
main_httpc_responsesuccess (java line: 324)
org.json.JSONException: End of input at character 0 of
at org.json.JSONTokener.syntaxError(JSONTokener.java:446)
at org.json.JSONTokener.nextValue(JSONTokener.java:93)
at anywheresoftware.b4a.objects.collections.JSONParser.NextObject(JSONParser.java:45)
at t.t.c.main._httpc_responsesuccess(main.java:324)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:136)
at anywheresoftware.b4a.BA$2.run(BA.java:244)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:144)
at android.app.ActivityThread.main(ActivityThread.java:4937)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)
org.json.JSONException: End of input at character 0 of
Connected to B4A-Bridge (Wifi)
Connected to B4A-Bridge (Wifi)
** Activity (main) Pause, UserClosed = false **
Installing file.
PackageAdded: package:t.t.c
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
main_httpc_responsesuccess (java line: 324)
org.json.JSONException: End of input at character 0 of
at org.json.JSONTokener.syntaxError(JSONTokener.java:446)
at org.json.JSONTokener.nextValue(JSONTokener.java:93)
at anywheresoftware.b4a.objects.collections.JSONParser.NextObject(JSONParser.java:45)
at t.t.c.main._httpc_responsesuccess(main.java:324)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:136)
at anywheresoftware.b4a.BA$2.run(BA.java:244)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:144)
at android.app.ActivityThread.main(ActivityThread.java:4937)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)
org.json.JSONException: End of input at character 0 of
** Activity (main) Pause, UserClosed = false **
Installing file.
PackageAdded: package:t.t.c
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
main_httpc_responsesuccess (java line: 324)
org.json.JSONException: End of input at character 0 of
at org.json.JSONTokener.syntaxError(JSONTokener.java:446)
at org.json.JSONTokener.nextValue(JSONTokener.java:93)
at anywheresoftware.b4a.objects.collections.JSONParser.NextObject(JSONParser.java:45)
at t.t.c.main._httpc_responsesuccess(main.java:324)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:136)
at anywheresoftware.b4a.BA$2.run(BA.java:244)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:144)
at android.app.ActivityThread.main(ActivityThread.java:4937)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)
org.json.JSONException: End of input at character 0 of
 

Fox

Active Member
Licensed User
Longtime User
Installing file.
** Activity (main) Pause, UserClosed = false **
PackageAdded: package:t.t.c
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
[]
main_httpc_responsesuccess (java line: 326)
org.json.JSONException: End of input at character 0 of
at org.json.JSONTokener.syntaxError(JSONTokener.java:446)
at org.json.JSONTokener.nextValue(JSONTokener.java:93)
at anywheresoftware.b4a.objects.collections.JSONParser.NextArray(JSONParser.java:57)
at t.t.c.main._httpc_responsesuccess(main.java:326)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:136)
at anywheresoftware.b4a.BA$2.run(BA.java:244)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:144)
at android.app.ActivityThread.main(ActivityThread.java:4937)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)
org.json.JSONException: End of input at character 0 of
 

Fox

Active Member
Licensed User
Longtime User
Code working perfect but not on my HTC Desire that was the problem. Thanks to all guys (Penko, Timo, thedesolatesoul, NJDude) for the fantastic support.
 

Fox

Active Member
Licensed User
Longtime User
Code working perfect but not on my HTC Desire that was the problem. Thanks to all guys (Penko, Timo, thedesolatesoul, NJDude) for the fantastic support.

PHP Code from me:

B4X:
$conn_DB=mysql_connect($hst,$usr,$pwd) or die(mysql_error());
mysql_select_db($db) or die(mysql_error());

$query="SELECT * FROM gtrial WHERE imei = '$imi' ";
$result=mysql_query($query,$conn_DB) or die(mysql_error());
$numrows=mysql_num_rows($result);

If ($numrows == 0) {
$restano=3;
$queryINS="INSERT INTO gtrial (imei,startsleft) VALUES ('$imi',$restano)";
mysql_query($queryINS);
                    }
else if ($numrows > 0) {
//never > 1 anyway
$restano=mysql_result($result,0,'startsleft'); 
        if($restano>0)         {
            $restano=$restano -1;
$queryUPDT="UPDATE gtrial SET startsleft = $restano WHERE imei='$imi'";
mysql_query($queryUPDT);
                            }
                        }
                        
$queryOUT="SELECT * FROM gtrial WHERE imei = '$imi' ";
$output=mysql_query($queryOUT);    

$rows = array();
    while($r = mysql_fetch_assoc($output)) {
        $rows[] = $r;
    }
    print json_encode($rows);
?>
 

Fox

Active Member
Licensed User
Longtime User
ok the problem should be the php file.. the Database give an empty response to the imei if you run it on emulator works (no imei) but with an real divice get an error at this line: m=JSON.NextObject

and the log get an result this []

maybe anyone can take a look over the php file it is the same as timo posted.
 
Top