Ücretli uygulama olarak piyasaya sürmek istediğim bir uygulamam var. 5 gün gibi bir zaman sınırı olan "deneme" sürümü olan başka bir sürüme sahip olmak istiyorum.
Bunu nasıl yapabilirim?
Ücretli uygulama olarak piyasaya sürmek istediğim bir uygulamam var. 5 gün gibi bir zaman sınırı olan "deneme" sürümü olan başka bir sürüme sahip olmak istiyorum.
Bunu nasıl yapabilirim?
Yanıtlar:
Şu anda çoğu geliştirici, aşağıdaki 3 teknikten birini kullanarak bunu başarmaktadır.
İlk yaklaşım kolayca atlatılır, uygulamayı ilk çalıştırdığınızda tarihi / saati bir dosyaya, veritabanına veya paylaşılan tercihlere kaydedin ve bu kontrolden sonra uygulamayı her çalıştırdığınızda deneme süresinin bitip bitmediğini kontrol edin. Bunu aşmak kolaydır, çünkü kaldırma ve yeniden yükleme kullanıcının başka bir deneme süresine sahip olmasına izin verir.
İkinci yaklaşımın üstesinden gelmek daha zordur, ancak yine de aşılabilir. Sabit kodlu bir saatli bomba kullanın. Temel olarak bu yaklaşımla, deneme için bir bitiş tarihini sabit kodlayacaksınız ve uygulamayı indirip kullanan tüm kullanıcılar aynı anda uygulamayı kullanamayacak. Bu yaklaşımı, uygulaması kolay olduğu için kullandım ve çoğunlukla üçüncü tekniğin sıkıntısından geçmek istemedim. Kullanıcılar, telefonlarındaki tarihi manuel olarak değiştirerek bunu aşabilirler, ancak çoğu kullanıcı böyle bir şey yapmak için zahmete girmez.
Üçüncü teknik, yapmak istediğinizi gerçekten başarmak için duyduğum tek yoldur. Bir sunucu kurmanız gerekecek ve ardından uygulamanız her başlatıldığında, uygulamanız telefonlara benzersiz tanımlayıcıyı sunucuya gönderir . Sunucunun bu telefon kimliği için bir girişi yoksa, yeni bir tane oluşturur ve saati not eder. Sunucunun telefon kimliği için bir girişi varsa, deneme süresinin dolup dolmadığını görmek için basit bir kontrol yapar. Ardından, deneme süresinin dolduğu kontrolün sonuçlarını uygulamanıza geri iletir. Bu yaklaşım atlatılamaz, ancak bir web sunucusu kurmayı gerektirir.
Bu kontrolleri onCreate'te yapmak her zaman iyi bir uygulamadır. Son kullanma süresi sona erdiyse , uygulamanın tam sürümüne bir pazar bağlantısı içeren bir AlertDialog açılır . Yalnızca bir "Tamam" düğmesi ekleyin ve kullanıcı "Tamam" ı tıkladığında etkinliği sonlandırmak için "bitir ()" çağrısı yapın.
Android Studio projenize kolayca bırakabileceğiniz bir Android Deneme SDK'sı geliştirdim ve sizin için tüm sunucu tarafı yönetimini (çevrimdışı yetkisiz kullanım süreleri dahil) halledecektir.
Kullanmak için basitçe
Kitaplığı ana modülünüze ekleyin build.gradle
dependencies {
compile 'io.trialy.library:trialy:1.0.2'
}
Ana etkinliğinizin onCreate()
yönteminde kitaplığı başlatın
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Initialize the library and check the current trial status on every launch
Trialy mTrialy = new Trialy(mContext, "YOUR_TRIALY_APP_KEY");
mTrialy.checkTrial(TRIALY_SKU, mTrialyCallback);
}
Geri arama işleyicisi ekleyin:
private TrialyCallback mTrialyCallback = new TrialyCallback() {
@Override
public void onResult(int status, long timeRemaining, String sku) {
switch (status){
case STATUS_TRIAL_JUST_STARTED:
//The trial has just started - enable the premium features for the user
break;
case STATUS_TRIAL_RUNNING:
//The trial is currently running - enable the premium features for the user
break;
case STATUS_TRIAL_JUST_ENDED:
//The trial has just ended - block access to the premium features
break;
case STATUS_TRIAL_NOT_YET_STARTED:
//The user hasn't requested a trial yet - no need to do anything
break;
case STATUS_TRIAL_OVER:
//The trial is over
break;
}
Log.i("TRIALY", "Trialy response: " + Trialy.getStatusMessage(status));
}
};
Bir deneme başlatmak için, mTrialy.startTrial("YOUR_TRIAL_SKU", mTrialyCallback);
uygulama anahtarınızı arayın ve deneme SKU'sunu Trialy geliştirici panonuzda bulabilirsiniz .
Bu eski bir soru ama her neyse, belki bu birine yardımcı olur.
En basit yaklaşımla gitmek istemeniz durumunda ( uygulama kaldırılırsa / yeniden yüklenirse veya kullanıcı cihazın tarihini manuel olarak değiştirirse başarısız olur ), şu şekilde olabilir:
private final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
private final long ONE_DAY = 24 * 60 * 60 * 1000;
@Override
protected void onCreate(Bundle state){
SharedPreferences preferences = getPreferences(MODE_PRIVATE);
String installDate = preferences.getString("InstallDate", null);
if(installDate == null) {
// First run, so save the current date
SharedPreferences.Editor editor = preferences.edit();
Date now = new Date();
String dateString = formatter.format(now);
editor.putString("InstallDate", dateString);
// Commit the edits!
editor.commit();
}
else {
// This is not the 1st run, check install date
Date before = (Date)formatter.parse(installDate);
Date now = new Date();
long diff = now.getTime() - before.getTime();
long days = diff / ONE_DAY;
if(days > 30) { // More than 30 days?
// Expired !!!
}
}
...
}
getTime
değildir getTimeInMillis
.
Bu soru ve snctln'nin cevabı, bana lisans tezim olarak yöntem 3'e dayalı bir çözüm üzerinde çalışmaya ilham verdi. Şu anki durumun verimli kullanım için olmadığını biliyorum, ancak bunun hakkında ne düşündüğünüzü duymak isterim! Böyle bir sistem kullanır mısın? Bunu bir bulut hizmeti olarak görmek ister misiniz (bir sunucuyu yapılandırmada sorun yaşamıyorsanız)? Güvenlik sorunları veya kararlılık nedenleri hakkında endişeli misiniz?
Lisans prosedürünü bitirir bitirmez yazılım üzerinde çalışmaya devam etmek istiyorum. Bu yüzden şimdi geri bildiriminize ihtiyacım olan zaman!
Kaynak kodu GitHub https://github.com/MaChristmann/mobile-trial üzerinde barındırılmaktadır
Sistemle ilgili bazı bilgiler: - Sistemin üç bölümü, bir Android kitaplığı, bir node.js sunucusu ve birden çok deneme uygulamasını ve yayıncı / geliştirici hesaplarını yönetmek için bir yapılandırıcı vardır.
Yalnızca zamana dayalı denemeleri destekler ve telefon kimliği yerine (oyun mağazası veya diğer) hesabınızı kullanır.
Android kitaplığı için Google Play lisans doğrulama kitaplığına dayanır. Bunu node.js sunucusuna bağlanmak için değiştirdim ve ayrıca kütüphane bir kullanıcının sistem tarihini değiştirip değiştirmediğini tanımaya çalışıyor. Ayrıca, alınan bir deneme lisansını AES şifreli Paylaşılan Tercihler'de önbelleğe alır. Önbelleğin geçerli zamanını yapılandırıcı ile yapılandırabilirsiniz. Bir kullanıcı "verileri temizlerse", kitaplık sunucu tarafı denetimi zorlar.
Sunucu https kullanıyor ve ayrıca lisans kontrol yanıtını dijital olarak imzalıyor. Ayrıca CRUD deneme uygulamaları ve kullanıcıları (yayıncı ve geliştirici) için bir API'ye sahiptir. Lisanslama Doğrulama Kitaplığı'na benzer geliştiriciler, deneme uygulamasında davranış uygulamalarını test sonucuyla test edebilir. Böylece yapılandırıcıda, lisans yanıtınızı açıkça "lisanslı", "lisanssız" veya "sunucu hatası" olarak ayarlayabilirsiniz.
Uygulamanızı can sıkıcı yeni bir özellikle güncellerseniz, herkesin tekrar denemesini isteyebilirsiniz. Konfigüratörde, lisansı sona ermiş kullanıcılar için deneme lisansını, bunu tetiklemesi gereken bir sürüm kodu belirleyerek yenileyebilirsiniz. Örneğin, kullanıcı uygulamanızı sürüm kodu 3 üzerinde çalıştırıyor ve siz onun sürüm kodu 4'ün özelliklerini denemesini istiyorsunuz. Uygulamayı güncellerse veya yeniden yüklerse, sunucu en son hangi sürümü denediğini bildiği için tam deneme süresini tekrar kullanabilir. zaman.
Her şey Apache 2.0 lisansı altında
Bunu yapmanın en kolay ve en iyi yolu, BackupSharedPreferences uygulamasıdır.
Uygulama kaldırılıp yeniden yüklense bile tercihler korunur.
Kurulum tarihini bir tercih olarak kaydedin ve gitmeniz iyi olur.
İşte teori: http://developer.android.com/reference/android/app/backup/SharedPreferencesBackupHelper.html
İşte örnek: Android SharedPreferences Yedeklemesi Çalışmıyor
Yaklaşım 4: Uygulama yükleme zamanını kullanın.
API seviyesi 9'dan beri (Android 2.3.2, 2.3.1, Android 2.3, GINGERBREAD) ilkInstallTime ve lastUpdateTime içinde PackageInfo
.
Daha fazlasını okumak için: Android'den uygulama yükleme süresi nasıl alınır?
Artık android ücretsiz deneme aboneliğinin son sürümünde, tüm uygulamanızın özelliklerinin kilidini yalnızca uygulama içinden ücretsiz deneme süresi için aboneliği satın aldıktan sonra açabilirsiniz. Bu, kullanıcının uygulamanızı bir deneme süresi boyunca kullanmasına izin verecektir, uygulama deneme süresinden sonra hala kaldırılmışsa, abonelik parası size aktarılacaktır. Denemedim, sadece bir fikir paylaşıyorum.
Kanımca, bunu yapmanın en iyi yolu Firebase Realtime Database'i kullanmaktır:
1) Uygulamanıza Firebase desteği ekleyin
2) Kullanıcının kaydolmasına veya ne yaptığınızı bilmesine gerek kalmaması için 'Anonim kimlik doğrulama'yı seçin. Bunun şu anda kimliği doğrulanmış kullanıcı hesabına bağlanması garanti edilir ve bu nedenle cihazlar arasında çalışacaktır.
3) 'installed_date' için bir değer ayarlamak üzere Realtime Database API'sini kullanın. Başlatma zamanında, bu değeri alın ve bunu kullanın.
Ben de aynısını yaptım ve harika çalışıyor. Bunu kaldırma / yeniden yüklemelerde test edebildim ve gerçek zamanlı veritabanındaki değer aynı kaldı. Bu şekilde deneme süreniz birden fazla kullanıcı cihazında çalışır. Hatta yükleme_tarihinizin sürümünü, uygulamanın her yeni ana sürüm için Deneme tarihini 'sıfırlaması' için bile değiştirebilirsiniz.
GÜNCELLEME : Biraz daha test ettikten sonra, farklı cihazlara sahip olmanız ve yeniden yüklemeler arasında garanti edilmemesi durumunda anonim Firebase'in farklı bir kimlik tahsis ettiği görülüyor: / Garantili tek yol Firebase'i kullanmak, ancak Google'a bağlamaktır. hesabı. Bu işe yaramalı, ancak kullanıcının önce oturum açması / kaydolması gerektiğinde ekstra bir adım gerektirecektir.
Şimdiye kadar, yedeklenmiş tercihlere karşı kontrol etme konusunda biraz daha az zarif bir yaklaşımla ve kurulumdan sonra tercihlerde saklanan bir tarihle sonuçlandım. Bu, bir kişinin uygulamayı yeniden yüklemesinin ve önceden eklenen tüm verileri yeniden girmesinin anlamsız olduğu, ancak basit bir oyunda işe yaramayacağı veri merkezli uygulamalar için işe yarar.
Bu ve diğer konulardaki tüm seçeneklere baktıktan sonra, bunlar benim bulgularım
Paylaşılan tercihler, veritabanı Android ayarlarında silinebilir, bir uygulama yeniden yüklendikten sonra kaybolur. Android'in yedekleme mekanizması ile yedeklenebilir ve bir yeniden yüklemeden sonra geri yüklenir. Yedekleme her zaman mevcut olmayabilir, ancak çoğu cihazda olmalıdır
Harici depolama (bir dosyaya yazma) Uygulamanın özel dizinine yazmazsak, ayarların temizlemesinden veya yeniden yüklemeden etkilenmez . Ancak: daha yeni android sürümlerinde çalışma zamanında kullanıcıdan izin istemenizi gerektirir , bu nedenle bu muhtemelen yalnızca yine de bu izne ihtiyacınız varsa uygulanabilir. Ayrıca yedeklenebilir.
PackageInfo.firstInstallTime Bir yeniden yüklemeden sonra sıfırlanır, ancak güncellemeler boyunca kararlıdır
Bir hesapta oturum açın Firebase aracılığıyla veya kendi sunucunuzdaki bir Google hesabı farketmez: deneme hesaba bağlıdır. Yeni bir hesap oluşturmak denemeyi sıfırlayacaktır.
Firebase anonim oturum açma Bir kullanıcı anonim olarak oturum açabilir ve Firebase'de onun için veri depolayabilirsiniz. Ancak görünüşe göre uygulamanın yeniden yüklenmesi ve belki de diğer belgelenmemiş olaylar kullanıcıya deneme sürelerini sıfırlayarak yeni bir anonim kimlik verebilir . (Google'ın kendisi bu konuda çok fazla belge sağlamaz)
ANDROID_ID mevcut olmayabilir ve bazı durumlarda değişebilir , örneğin fabrika ayarlarına sıfırlama. Cihazları tanımlamak için bunu kullanmanın iyi bir fikir olup olmadığına dair görüşler farklı görünmektedir.
Play Reklam Kimliği Kullanıcı tarafından sıfırlanabilir. Reklam takibini devre dışı bırakarak kullanıcı tarafından devre dışı bırakılabilir.
Bir yeniden kurulumda Örnek Kimliği Sıfırlama . Bir güvenlik olayı durumunda sıfırlayın. Uygulamanız tarafından sıfırlanabilir.
Hangi yöntemlerin (kombinasyonunun) işinize yarayacağı, uygulamanıza ve ortalama John'un başka bir deneme süresi kazanmak için ne kadar çaba göstereceğini düşündüğünüze bağlıdır. Kararsızlıkları nedeniyle yalnızca anonim Firebase ve Reklam Kimliği kullanmaktan kaçınmanızı öneririm . Çok faktörlü bir yaklaşım, en iyi sonuçları verecek gibi görünüyor. Sizin için hangi faktörlerin mevcut olduğu, uygulamanıza ve izinlerine bağlıdır.
Kendi uygulamam için paylaşılan tercihler + firstInstallTime + tercihlerin yedeklemesinin en az müdahaleci ama aynı zamanda yeterince etkili yöntem olduğunu buldum. Yalnızca deneme başlangıç zamanını paylaşılan tercihlerde kontrol edip kaydettikten sonra bir yedekleme talep ettiğinizden emin olmalısınız. Paylaşılan Tercihlerdeki değerler, firstInstallTime'a göre önceliğe sahip olmalıdır. Daha sonra kullanıcının uygulamayı yeniden yüklemesi, bir kez çalıştırması ve ardından denemeyi sıfırlamak için uygulamanın verilerini temizlemesi gerekir ki bu oldukça fazla bir iştir. Yedek aktarımı olmayan cihazlarda kullanıcı, denemeyi basitçe yeniden yükleyerek sıfırlayabilir.
Bu yaklaşımı genişletilebilir bir kitaplık olarak kullanıma sundum .
Tanım olarak, piyasadaki tüm ücretli Android uygulamaları satın alındıktan sonra 24 saat değerlendirilebilir.
24 saat sonra "Kaldır" olarak değişen bir "Kaldır ve Geri Ödeme" düğmesi vardır.
Bu düğmenin çok belirgin olduğunu iddia ediyorum!
Aynı sorunu ararken bu soruyla karşılaşıyorum , iz uygulamasının süresinin dolup dolmadığını kontrol etmek için http://www.timeapi.org/utc/now veya başka bir tarih api gibi ücretsiz tarih api kullanabiliriz diye düşünüyorum . Bu yol, demoyu sunmak istiyorsanız ve ödeme konusunda endişeleriniz varsa ve hizmet süresi demosunu düzeltmek istiyorsanız etkilidir. :)
aşağıdaki kodu bulun
public class ValidationActivity extends BaseMainActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume() {
processCurrentTime();
super.onResume();
}
private void processCurrentTime() {
if (!isDataConnectionAvailable(ValidationActivity.this)) {
showerrorDialog("No Network coverage!");
} else {
String urlString = "http://api.timezonedb.com/?zone=Europe/London&key=OY8PYBIG2IM9";
new CallAPI().execute(urlString);
}
}
private void showerrorDialog(String data) {
Dialog d = new Dialog(ValidationActivity.this);
d.setTitle("LS14");
TextView tv = new TextView(ValidationActivity.this);
tv.setText(data);
tv.setPadding(20, 30, 20, 50);
d.setContentView(tv);
d.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
finish();
}
});
d.show();
}
private void checkExpiry(int isError, long timestampinMillies) {
long base_date = 1392878740000l;// feb_19 13:8 in GMT;
// long expiryInMillies=1000*60*60*24*5;
long expiryInMillies = 1000 * 60 * 10;
if (isError == 1) {
showerrorDialog("Server error, please try again after few seconds");
} else {
System.out.println("fetched time " + timestampinMillies);
System.out.println("system time -" + (base_date + expiryInMillies));
if (timestampinMillies > (base_date + expiryInMillies)) {
showerrorDialog("Demo version expired please contact vendor support");
System.out.println("expired");
}
}
}
private class CallAPI extends AsyncTask<String, String, String> {
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
@Override
protected String doInBackground(String... params) {
String urlString = params[0]; // URL to call
String resultToDisplay = "";
InputStream in = null;
// HTTP Get
try {
URL url = new URL(urlString);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream());
resultToDisplay = convertStreamToString(in);
} catch (Exception e) {
System.out.println(e.getMessage());
return e.getMessage();
}
return resultToDisplay;
}
protected void onPostExecute(String result) {
int isError = 1;
long timestamp = 0;
if (result == null || result.length() == 0 || result.indexOf("<timestamp>") == -1 || result.indexOf("</timestamp>") == -1) {
System.out.println("Error $$$$$$$$$");
} else {
String strTime = result.substring(result.indexOf("<timestamp>") + 11, result.indexOf("</timestamp>"));
System.out.println(strTime);
try {
timestamp = Long.parseLong(strTime) * 1000;
isError = 0;
} catch (NumberFormatException ne) {
}
}
checkExpiry(isError, timestamp);
}
} // end CallAPI
public static boolean isDataConnectionAvailable(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = connectivityManager.getActiveNetworkInfo();
if (info == null)
return false;
return connectivityManager.getActiveNetworkInfo().isConnected();
}
public String convertStreamToString(InputStream is) throws IOException {
if (is != null) {
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
} finally {
is.close();
}
return writer.toString();
} else {
return "";
}
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
çalışma çözümü .....
İşte benimkini nasıl yaptım, biri deneme etkinliği olan diğeri olmadan 2 uygulama oluşturdum.
Mağazayı ücretli uygulama olarak oynamak için deneme etkinliği olmayan birini yükledim,
ve ücretsiz uygulama olarak deneme etkinliği olan.
İlk başlatıldığında ücretsiz uygulama, deneme ve mağaza satın alma seçeneklerine sahiptir, kullanıcı mağazadan satın almayı seçerse, kullanıcının satın alması için mağazaya yönlendirir, ancak kullanıcı denemeyi tıklarsa deneme etkinliğine götürür.
NB: @snctln gibi 3. seçeneği kullandım ama değişikliklerle
ilk olarak , cihaz saatine bağlı değildim, zamanımı db'ye deneme kaydını yapan php dosyasından aldım,
ikinci olarak , her bir cihazı benzersiz şekilde tanımlamak için cihazın seri numarasını kullandım,
son olarak , uygulama kendi zamanına değil sunucu bağlantısından dönen zaman değerine bağlıdır, bu nedenle sistem yalnızca cihaz seri numarası değiştirilirse engellenebilir, bu da bir kullanıcı için oldukça streslidir.
işte kodum burada (Deneme etkinliği için):
package com.example.mypackage.my_app.Start_Activity.activity;
import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.telephony.TelephonyManager;
import android.view.KeyEvent;
import android.widget.TextView;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.example.onlinewisdom.cbn_app.R;
import com.example.mypackage.my_app.Start_Activity.app.Config;
import com.example.mypackage.my_app.Start_Activity.data.TrialData;
import com.example.mypackage.my_app.Start_Activity.helper.connection.Connection;
import com.google.gson.Gson;
import org.json.JSONObject;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import cn.pedant.SweetAlert.SweetAlertDialog;
public class Trial extends AppCompatActivity {
Connection check;
SweetAlertDialog pDialog;
TextView tvPleaseWait;
private static final int MY_PERMISSIONS_REQUEST_READ_PHONE_STATE = 0;
String BASE_URL = Config.BASE_URL;
String BASE_URL2 = BASE_URL+ "/register_trial/"; //http://ur link to ur API
//KEY
public static final String KEY_IMEI = "IMEINumber";
private final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
private final long ONE_DAY = 24 * 60 * 60 * 1000;
SharedPreferences preferences;
String installDate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_trial);
preferences = getPreferences(MODE_PRIVATE);
installDate = preferences.getString("InstallDate", null);
pDialog = new SweetAlertDialog(this, SweetAlertDialog.PROGRESS_TYPE);
pDialog.getProgressHelper().setBarColor(Color.parseColor("#008753"));
pDialog.setTitleText("Loading...");
pDialog.setCancelable(false);
tvPleaseWait = (TextView) findViewById(R.id.tvPleaseWait);
tvPleaseWait.setText("");
if(installDate == null) {
//register app for trial
animateLoader(true);
CheckConnection();
} else {
//go to main activity and verify there if trial period is over
Intent i = new Intent(Trial.this, MainActivity.class);
startActivity(i);
// close this activity
finish();
}
}
public void CheckConnection() {
check = new Connection(this);
if (check.isConnected()) {
//trigger 'loadIMEI'
loadIMEI();
} else {
errorAlert("Check Connection", "Network is not detected");
tvPleaseWait.setText("Network is not detected");
animateLoader(false);
}
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
//Changes 'back' button action
if (keyCode == KeyEvent.KEYCODE_BACK) {
finish();
}
return true;
}
public void animateLoader(boolean visibility) {
if (visibility)
pDialog.show();
else
pDialog.hide();
}
public void errorAlert(String title, String msg) {
new SweetAlertDialog(this, SweetAlertDialog.ERROR_TYPE)
.setTitleText(title)
.setContentText(msg)
.show();
}
/**
* Called when the 'loadIMEI' function is triggered.
*/
public void loadIMEI() {
// Check if the READ_PHONE_STATE permission is already available.
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
// READ_PHONE_STATE permission has not been granted.
requestReadPhoneStatePermission();
} else {
// READ_PHONE_STATE permission is already been granted.
doPermissionGrantedStuffs();
}
}
/**
* Requests the READ_PHONE_STATE permission.
* If the permission has been denied previously, a dialog will prompt the user to grant the
* permission, otherwise it is requested directly.
*/
private void requestReadPhoneStatePermission() {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_PHONE_STATE)) {
// Provide an additional rationale to the user if the permission was not granted
// and the user would benefit from additional context for the use of the permission.
// For example if the user has previously denied the permission.
new AlertDialog.Builder(Trial.this)
.setTitle("Permission Request")
.setMessage(getString(R.string.permission_read_phone_state_rationale))
.setCancelable(false)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//re-request
ActivityCompat.requestPermissions(Trial.this,
new String[]{Manifest.permission.READ_PHONE_STATE},
MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);
}
})
.setIcon(R.drawable.warning_sigh)
.show();
} else {
// READ_PHONE_STATE permission has not been granted yet. Request it directly.
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE},
MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);
}
}
/**
* Callback received when a permissions request has been completed.
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == MY_PERMISSIONS_REQUEST_READ_PHONE_STATE) {
// Received permission result for READ_PHONE_STATE permission.est.");
// Check if the only required permission has been granted
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// READ_PHONE_STATE permission has been granted, proceed with displaying IMEI Number
//alertAlert(getString(R.string.permision_available_read_phone_state));
doPermissionGrantedStuffs();
} else {
alertAlert(getString(R.string.permissions_not_granted_read_phone_state));
}
}
}
private void alertAlert(String msg) {
new AlertDialog.Builder(Trial.this)
.setTitle("Permission Request")
.setMessage(msg)
.setCancelable(false)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// do somthing here
}
})
.setIcon(R.drawable.warning_sigh)
.show();
}
private void successAlert(String msg) {
new SweetAlertDialog(this, SweetAlertDialog.SUCCESS_TYPE)
.setTitleText("Success")
.setContentText(msg)
.setConfirmText("Ok")
.setConfirmClickListener(new SweetAlertDialog.OnSweetClickListener() {
@Override
public void onClick(SweetAlertDialog sDialog) {
sDialog.dismissWithAnimation();
// Prepare intent which is to be triggered
//Intent i = new Intent(Trial.this, MainActivity.class);
//startActivity(i);
}
})
.show();
}
public void doPermissionGrantedStuffs() {
//Have an object of TelephonyManager
TelephonyManager tm =(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
//Get IMEI Number of Phone //////////////// for this example i only need the IMEI
String IMEINumber = tm.getDeviceId();
/************************************************
* **********************************************
* This is just an icing on the cake
* the following are other children of TELEPHONY_SERVICE
*
//Get Subscriber ID
String subscriberID=tm.getDeviceId();
//Get SIM Serial Number
String SIMSerialNumber=tm.getSimSerialNumber();
//Get Network Country ISO Code
String networkCountryISO=tm.getNetworkCountryIso();
//Get SIM Country ISO Code
String SIMCountryISO=tm.getSimCountryIso();
//Get the device software version
String softwareVersion=tm.getDeviceSoftwareVersion()
//Get the Voice mail number
String voiceMailNumber=tm.getVoiceMailNumber();
//Get the Phone Type CDMA/GSM/NONE
int phoneType=tm.getPhoneType();
switch (phoneType)
{
case (TelephonyManager.PHONE_TYPE_CDMA):
// your code
break;
case (TelephonyManager.PHONE_TYPE_GSM)
// your code
break;
case (TelephonyManager.PHONE_TYPE_NONE):
// your code
break;
}
//Find whether the Phone is in Roaming, returns true if in roaming
boolean isRoaming=tm.isNetworkRoaming();
if(isRoaming)
phoneDetails+="\nIs In Roaming : "+"YES";
else
phoneDetails+="\nIs In Roaming : "+"NO";
//Get the SIM state
int SIMState=tm.getSimState();
switch(SIMState)
{
case TelephonyManager.SIM_STATE_ABSENT :
// your code
break;
case TelephonyManager.SIM_STATE_NETWORK_LOCKED :
// your code
break;
case TelephonyManager.SIM_STATE_PIN_REQUIRED :
// your code
break;
case TelephonyManager.SIM_STATE_PUK_REQUIRED :
// your code
break;
case TelephonyManager.SIM_STATE_READY :
// your code
break;
case TelephonyManager.SIM_STATE_UNKNOWN :
// your code
break;
}
*/
// Now read the desired content to a textview.
//tvPleaseWait.setText(IMEINumber);
UserTrialRegistrationTask(IMEINumber);
}
/**
* Represents an asynchronous login task used to authenticate
* the user.
*/
private void UserTrialRegistrationTask(final String IMEINumber) {
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, BASE_URL2+IMEINumber, null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Gson gson = new Gson();
TrialData result = gson.fromJson(String.valueOf(response), TrialData.class);
animateLoader(false);
if ("true".equals(result.getError())) {
errorAlert("Error", result.getResult());
tvPleaseWait.setText("Unknown Error");
} else if ("false".equals(result.getError())) {
//already created install/trial_start date using the server
// so just getting the date called back
Date before = null;
try {
before = (Date)formatter.parse(result.getResult());
} catch (ParseException e) {
e.printStackTrace();
}
Date now = new Date();
assert before != null;
long diff = now.getTime() - before.getTime();
long days = diff / ONE_DAY;
// save the date received
SharedPreferences.Editor editor = preferences.edit();
editor.putString("InstallDate", String.valueOf(days));
// Commit the edits!
editor.apply();
//go to main activity and verify there if trial period is over
Intent i = new Intent(Trial.this, MainActivity.class);
startActivity(i);
// close this activity
finish();
//successAlert(String.valueOf(days));
//if(days > 5) { // More than 5 days?
// Expired !!!
//}
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
animateLoader(false);
//errorAlert(error.toString());
errorAlert("Check Connection", "Could not establish a network connection.");
tvPleaseWait.setText("Network is not detected");
}
})
{
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put(KEY_IMEI, IMEINumber);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(jsonObjectRequest);
}
}
PHP dosyam şöyle görünüyor (bir REST-ince teknolojisi):
/**
* registerTrial
*/
public function registerTrial($IMEINumber) {
//check if $IMEINumber already exist
// Instantiate DBH
$DBH = new PDO_Wrapper();
$DBH->query("SELECT date_reg FROM trials WHERE device_id = :IMEINumber");
$DBH->bind(':IMEINumber', $IMEINumber);
// DETERMINE HOW MANY ROWS OF RESULTS WE GOT
$totalRows_registered = $DBH->rowCount();
// DETERMINE HOW MANY ROWS OF RESULTS WE GOT
$results = $DBH->resultset();
if (!$IMEINumber) {
return 'Device serial number could not be determined.';
} else if ($totalRows_registered > 0) {
$results = $results[0];
$results = $results['date_reg'];
return $results;
} else {
// Instantiate variables
$trial_unique_id = es_generate_guid(60);
$time_reg = date('H:i:s');
$date_reg = date('Y-m-d');
$DBH->beginTransaction();
// opening db connection
//NOW Insert INTO DB
$DBH->query("INSERT INTO trials (time_reg, date_reg, date_time, device_id, trial_unique_id) VALUES (:time_reg, :date_reg, NOW(), :device_id, :trial_unique_id)");
$arrayValue = array(':time_reg' => $time_reg, ':date_reg' => $date_reg, ':device_id' => $IMEINumber, ':trial_unique_id' => $trial_unique_id);
$DBH->bindArray($arrayValue);
$subscribe = $DBH->execute();
$DBH->endTransaction();
return $date_reg;
}
}
daha sonra ana etkinlikte, kalan gün sayısını izlemek için paylaşılan tercihi (deneme etkinliğinde oluşturulan yükleme tarihi) kullanıyorum ve günler bittiyse ana etkinlik kullanıcı arayüzünü, satın almaları için mağazaya götüren bir mesajla engelliyorum.
Burada gördüğüm tek olumsuz taraf, bir Rogue kullanıcısı ücretli uygulamayı satın alırsa ve Zender gibi uygulamalarla paylaşmaya karar verirse, dosya paylaşımı veya hatta apk dosyasını insanların ücretsiz indirmesi için doğrudan bir sunucuda barındırmasıdır. Ama eminim yakında bu yanıtı buna bir çözümle veya çözüme bağlantıyla düzenleyeceğim.
Umarım bu bir ruhu kurtarır ... bir gün
Mutlu Kodlama ...
@snctln seçenek 3, çoğunun sahip olduğu php ve mysql yüklü bir web sunucusuna bir php dosyası ekleyerek kolayca yapılabilir.
Android tarafından HttpURLConnection kullanılarak URL'de bağımsız değişken olarak bir tanımlayıcı (cihaz kimliği, google hesabı veya ne isterseniz) iletilir ve php tabloda varsa ilk kurulum tarihini döndürür veya yeni bir satır ekler ve geçerli tarihi döndürür.
Benim için iyi çalışıyor.
Zamanım olursa bir kod göndereceğim!
İyi şanslar !