إنشاء الروبوت طلب المحاكمة التي تنتهي بعد فترة زمنية محددة

StackOverflow https://stackoverflow.com/questions/995719

سؤال

لدي طلب وهو أريد أن ضرب السوق التطبيق المدفوعة.أود الحصول على نسخة أخرى التي من شأنها أن تكون "محاكمة" نسخة مع الوقت الحد من يقول 5 أيام ؟

كيف يمكنني فعل هذا ؟

هل كانت مفيدة؟

المحلول

حاليا معظم المطورين ينجزون هذا باستخدام واحدة من التقنيات الثلاثة التالية.

يتم التحايل للنهج الأول بسهولة، في المرة الأولى التي تقوم فيها بتشغيل التطبيق حفظ التاريخ / الوقت إلى ملف أو قاعدة بيانات أو تفضيلات مشتركة وفي كل مرة تقوم فيها بتشغيل التطبيق بعد هذا الاختيار لمعرفة ما إذا كانت الفترة التجريبية قد انتهت. هذا سهل التحايل لأن إزالة تثبيت وإعادة تثبيت سيسمح للمستخدم بفترة تجريبية أخرى.

النهج الثاني أصعب التحايل على التحايل، ولكن لا يزال التحايل. استخدام قنبلة زمنية مشفرة بجد. في الأساس مع هذا النهج، ستكون الزمج الصعب تاريخ انتهاء المحاكمة، وجميع المستخدمين الذين يقومون بتنزيل واستخدام التطبيق سيتوقفون عن القدرة على استخدام التطبيق في نفس الوقت. لقد استخدمت هذا النهج لأنه من السهل التنفيذ والجزء الأكبر لم أشعر بالقلق من مشكلة التقنية الثالثة. يمكن للمستخدمين التحايل على هذا من خلال تغيير تاريخ هاتفهم يدويا، لكن معظم المستخدمين لن يذهبوا إلى مشكلة للقيام بمثل هذا الشيء.

هذه التقنية الثالثة هي الطريقة الوحيدة التي سمعت بها على أنها حقا أن تكون قادرة حقا على إنجاز ما تريد القيام به. سوف تضطر إلى إعداد خادم، ثم كلما بدأ تطبيقك يرسل تطبيقك الهواتف المعرف الفريد إلى الخادم. إذا لم يكن لدى الخادم إدخالا لهذا معرف الهاتف، فهذا يجعل واحدة جديدة وتلاحظ الوقت. إذا كان لدى الخادم إدخال معرف الهاتف، فهذا يقوم بفحص بسيط لمعرفة ما إذا كانت الفترة التجريبية انتهت صلاحيتها. ثم ينقل نتائج التحقق من انتهاء صلاحية التجربة إلى طلبك. يجب عدم التحايل هذا النهج، ولكنه يتطلب إعداد خادم الويب ومثله.

من الممارسات الجيدة دائما القيام بهذه الشيكات في OnCreate. إذا انتهت الصلاحية المنبثقة منبثقة alertdialog مع رابط السوق إلى النسخة الكاملة من التطبيق. تضمين فقط زر "موافق"، وبمجرد النقر فوق المستخدم على "موافق" إجراء مكالمة إلى "إنهاء ()" لإنهاء النشاط.

نصائح أخرى

لقد طورت الروبوت التجربة SDK. التي يمكنك ببساطة الانتقال إلى مشروع استوديو Android الخاص بك وسوف تعتني بجميع إدارة جانب الخادم لك (بما في ذلك فترات Grace غير المتصلة بالإنترنت).

لاستخدامها، ببساطة

أضف المكتبة إلى الوحدة النمطية الرئيسية build.gradle

dependencies {
  compile 'io.trialy.library:trialy:1.0.2'
}

تهيئة المكتبة في نشاطك الرئيسي onCreate() طريقة

@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);
}

إضافة معالج اتصال:

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));
    }

};

لبدء تجربة، اتصل mTrialy.startTrial("YOUR_TRIAL_SKU", mTrialyCallback);يمكن العثور على مفتاح التطبيق الخاص بك والمحاكمة SKU في Developer Developer Triory.

هذا سؤال قديم ولكن على أي حال، ربما هذا سوف يساعد شخص ما.

في حال كنت تريد الذهاب مع النهج الأكثر بساطة(أيّ سوف تفشل إذا يتم إلغاء تثبيت التطبيق / إعادة تثبيته أو إعادة تثبيته أو تغيير المستخدم يدويا)، فهذا هو كيف يمكن أن يكون:

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 !!!
        }
    }

    ...
}

يا شباب هذا السؤال وجواب snctln. ألهمتني للعمل على حل بناء على الطريقة الثالثة مثل أطروحة البكالوريوس الخاصة بي. أعرف أن الوضع الحالي ليس للاستخدام الإنتاجي ولكني أحب أن أسمع ما تفكر فيه! هل تستخدم هذا النظام؟ هل ترغب في رؤيته كخدمة سحابية (لا تواجه مشكلة في تكوين خادم)؟ تشعر بالقلق إزاء قضايا الأمن أو أسباب الاستقرار؟ في أقرب وقت انتهيت من إجراء البكالوريوس، أريد مواصلة العمل على البرنامج. حتى الآن الوقت الذي أحتاج ملاحظاتك!

يتم استضافة Sourcecode على جيثب https://github.com/machristmann/mobile-Trial.

بعض المعلومات حول النظام: - يحتوي النظام على ثلاثة أجزاء، مكتبة Android، خادم Node.js و Confecturator لإدارة تطبيقات تجريبية متعددة وحسابات Publisher / Developer.

  • يدعم فقط التجارب القائم على الوقت وتستخدم حسابك (تشغيل متجر أو غيرها) بدلا من معرف الهاتف.

  • بالنسبة لمكتبة Android، تعتمد على مكتبة التحقق من ترخيص Google Play. قمت بتعديله للاتصال بخادم Node.js وإلياء الإضافة تحاول المكتبة التعرف على ما إذا كان المستخدم غير تاريخ النظام. كما أنه يخفف من ترخيص تجريبي استرجاع في AES تفضيلات مشتركة مشتركة. يمكنك تكوين الوقت الصحيح من ذاكرة التخزين المؤقت مع التكوين. إذا كان لدى المستخدم "بيانات واضحة"، فستفرض المكتبة فحصا جانب الخادم.

  • يستخدم الخادم HTTPS وأيضا توقيع الرقمية استجابة التحقق من الترخيص. لديها أيضا تطبيقات API للمحاكمة CRUD والمستخدمين (الناشر والمطور). يمكن أن يختبر مطورو مكتبة المرشحات التشفير التشكيمي اختبار تنفيذ سلوكهم في التطبيق التجريبي مع نتيجة الاختبار. لذلك أنت في Configurator يمكنك تعيين استجابة الترخيص الخاصة بك على "مرخصة"، "غير مرخص" أو "خطأ خادم".

  • إذا قمت بتحديث تطبيقك باستخدام ميزة جديدة للركل، فقد ترغب في أن يحاول الجميع تجربة ذلك مرة أخرى. في Configurator، يمكنك تجديد الترخيص التجريبي للمستخدمين الذين لديهم تراخيص منتهية الصلاحية عن طريق تعيين إصدار إصدار يجب أن يؤدي إلى ذلك. على سبيل المثال، يقوم المستخدم بتشغيل التطبيق الخاص بك على VersionCode 3 UND الذي تريده لمحاولة ميزات النسخة الأصلية 4. إذا قام بتحديث التطبيق أو إعادة تثبيته، فهو قادر على استخدام الفترة التجريبية كاملة مرة أخرى لأن الخادم يعرف الإصدار الذي جربه الأخير الوقت.

  • كل شيء تحت رخصة Apache 2.0

الأسهل و أفضل الطريقة للقيام بذلك هي النسخ الاحتياطي المنفذ.

يتم الحفاظ على التفضيلات، حتى لو تم إلغاء تثبيت التطبيق وإعادة تثبيته.

ما عليك سوى حفظ تاريخ التثبيت كفضائح وأنت جيد للذهاب.

إليك النظرية:http://developer.android.com/Reference/Android/App/Backup/sharedpreferencesbackuphelper.html.

إليك المثال:Android SharedPreeferences النسخ الاحتياطي لا يعمل

نهج 4: استخدم وقت تثبيت التطبيق.

منذ API المستوى 9 (Android 2.3.2، 2.3.1، Android 2.3، Gingerbread) هناك FirstInstallime. و lastupdateTime. في PackageInfo.

لقراءة المزيد:كيفية الحصول على التطبيق تثبيت التطبيق من Android

الآن تم إضافة النسخة الأخيرة من الاشتراك في نسخة تجريبية مجانية Android، يمكنك فتح جميع ميزات التطبيق الخاصة بك فقط بعد شراء الاشتراك داخل التطبيق لفترة تجريبية مجانية. سيتيح ذلك للمستخدم استخدام تطبيقك لفترة تجريبية، إذا كان التطبيق لا يزال إلغاء تثبيته بعد الفترة التجريبية، فسيتم نقل أموال الاشتراك إليك. أنا لم أحاول، ولكن فقط تقاسم فكرة.

هنا وثائق

في رأيي، أفضل طريقة للقيام بذلك هي ببساطة استخدام قاعدة بيانات Firebase في الوقت الحقيقي:

1) إضافة دعم firebase إلى التطبيق الخاص بك

2) حدد "مصادقة مجهولة" بحيث لا يتعين على المستخدم الاشتراك أو حتى تعرف على ما تفعله. هذا مضمون الارتباط بحساب المستخدم المصادق عليه حاليا، وكذلك سيعمل عبر الأجهزة.

3) استخدم واجهة برمجة تطبيقات قاعدة البيانات في الوقت الحقيقي لتعيين قيمة ل "Office_Date". في وقت الإطلاق، ما عليك سوى استرجاع هذه القيمة واستخدام هذا.

لقد فعلت نفس الشيء ويعمل بشكل رائع. كنت قادرا على اختبار هذا عبر إلغاء التثبيت / إعادة التثبيت والقيمة في قاعدة بيانات الوقت الحقيقي لا تزال هي نفسها. وبهذه الطريقة تعمل الفترة التجريبية الخاصة بك عبر أجهزة مستخدم متعددة. يمكنك حتى الإصدار الخاص بك Install_Date بحيث "إعادة تعيين" تاريخ التجريبي لكل إصدار كبير جديد.

تحديث: بعد الاختبار أكثر قليلا، يبدو أن Firebase مجهول يبدو أنه يخصص معرفا مختلفا في حالة وجود أجهزة مختلفة وغير مضمون بين إعادة التثبيت: / الطريقة المضمونة الوحيدة هي استخدام Firebase ولكن ربطها بحساب Google وبعد يجب أن يعمل هذا، ولكنه يتطلب خطوة إضافية حيث يحتاج المستخدم أولا إلى تسجيل الدخول / الاشتراك.

لقد انتهى بهذا الأمر حتى الآن مع نهج أقل أناقة قليلا عن التدقيق ببساطة من تفضيلات احتياطية احتياطية وتاريخ مخزن في التفضيلات عند التثبيت. يعمل هذا في تطبيقات المراكز على البيانات حيث لا معنى له لشخص لإعادة تثبيت التطبيق وإعادة إدخال جميع البيانات مسبقا، ولكن لن تعمل في لعبة بسيطة.

بعد النظر في جميع الخيارات في هذه وغيرها من المواضيع ، هذه هي النتائج

مشترك تفضيلات قاعدة البيانات يمكن أن يتم مسح في إعدادات الروبوت, فقدت بعد إعادة تثبيت التطبيق. يمكن أن يكون احتياطيا مع الروبوت النسخ الاحتياطي آلية وسيتم استعادتها بعد إعادة تثبيت.النسخ الاحتياطي قد لا تكون متاحة دائما ، على الرغم من أن تكون على معظم الأجهزة

وحدة التخزين الخارجية (الكتابة إلى ملف) لا تتأثر واضح من الإعدادات أو إعادة تثبيت إذا كنا لا أكتب إلى التطبيق الخاص دليل.ولكن: يتطلب منك أن تسأل المستخدم عن الإذن في وقت التشغيل في أحدث إصدارات أندرويد, لذلك هذا هو على الارجح ممكنا فقط إذا كنت بحاجة إلى أن إذن على أي حال.يمكن أيضا أن يكون احتياطيا.

PackageInfo.firstInstallTime إعادة تعيين بعد تثبيت ولكن مستقرة عبر التحديثات

سجل الدخول إلى حساب لا يهم إذا كان حساب Google عبر Firebase أو واحد في الخادم الخاص بك:المحاكمة لا بد أن الحساب.صنع حساب جديد سوف إعادة المحاكمة.

Firebase مجهول تسجيل الدخول يمكنك تسجيل الدخول مستخدم مجهول و تخزين البيانات في قاعدة المدفعية.ولكن على ما يبدو إعادة تثبيت التطبيق و ربما البعض لا يحملون وثائق الأحداث قد تعطي مستخدم جديد مجهول الهوية, إعادة محاكمتهم مرة.(جوجل نفسها لا توفر الكثير من الوثائق على هذا)

ANDROID_ID قد لا تكون متوفرة و قد تتغير تحت ظروف معينة, ه.ز ضبط المصنع.الآراء حول ما إذا كان انها فكرة جيدة لاستخدام هذا إلى تحديد الأجهزة يبدو أن تختلف.

تلعب معرف الإعلانات ويجوز إعادة تعيين من قبل المستخدم. قد يتم تعطيل من قبل المستخدم باختياره من تتبع الإعلان.

معرف المثيل تعيين على تثبيت. إعادة تعيين في حالة الأمن الحدث.يمكن إعادة تعيين من قبل التطبيق الخاص بك.

وهو (الجمع) أساليب العمل بالنسبة لك يعتمد على التطبيق الخاص بك على مقدار الجهد تعتقد متوسط جون سوف يضع في كسب آخر الفترة التجريبية.أنصح توجيه واضح من استخدام فقط مجهول Firebase و معرف الإعلانات بسبب عدم الاستقرار.متعدد عامل نهج يبدو أنه سوف تسفر عن نتائج أفضل.العوامل التي تتوفر لك يعتمد على التطبيق الأذونات.

بلدي التطبيق وجدت مشترك تفضيلات + firstInstallTime + احتياطية من تفضيلات أن تكون أقل تطفلا ولكن أيضا طريقة فعالة بما فيه الكفاية.لديك للتأكد من أنه يمكنك فقط طلب بعد التحقق من النسخ الاحتياطي وتخزين المحاكمة وقت البدء في التفضيلات المشتركة.القيم المشتركة بادئات يجب أن يكون الأسبقية على firstInstallTime.ثم المستخدم إلى تثبيت التطبيق وتشغيله مرة واحدة ثم مسح بيانات التطبيق إلى إعادة المحاكمة ، وهو الكثير جدا من العمل.على الأجهزة دون النسخ الاحتياطي النقل يمكن للمستخدم إعادة المحاكمة ببساطة عن طريق إعادة تثبيت ، على الرغم من.

لقد اتخذت هذا النهج المتاحة الموسعة المكتبة.

حسب التعريف، الكل يمكن تقييم تطبيقات Android المدفوعة في السوق لمدة 24 ساعة بعد الشراء.

هناك زر "إلغاء التثبيت واسترداد" يتغير إلى "إلغاء التثبيت" بعد 24 ساعة.

كنت أقول هذا الزر بارز للغاية!

لقد صادفت هذا السؤال أثناء البحث عن نفس المشكلة، أعتقد أننا يمكن أن نستفيد تطبيق API مجانا http://www.timeapi.org/utc/now. أو بعض API التاريخ الآخر للتحقق من انتهاء صلاحية التطبيق. بهذه الطريقة فعالة إذا كنت ترغب في تقديم العرض التوضيحي والقلق من الدفع وتتطلب إصلاح حيازة التجريبي. :)

ابحث عن الرمز أدناه

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

}
}

حل العمل الخاص به .....

فيما يلي كيف ذهبت إلى الألغام، قمت بإنشاء 2 تطبيقات واحدة مع نشاط التجربة الآخر دون،

قمت بتحميل واحد دون نشاط تجريبي لتشغيل المتجر حسب التطبيق المدفوع،

والآخر مع نشاط التجربة كمجموع مجاني.

يحتوي التطبيق المجاني على الإطلاق الأول على خيارات للمحاكمة وشراء المتجر، إذا حدد المستخدم تخزين مخزن الشراء، فإنه يعيد توجيه إلى متجر للمستخدم للشراء ولكن إذا نقر المستخدم التجريبية، فإنه يأخذها إلى نشاط التجربة

ملحوظة: استخدمت الخيار 3 مثل snctln ولكن مع التعديلات

أول, ، لم أعتمد على وقت الجهاز، وحصلت على وقتي من ملف PHP الذي يقوم بتسجيل التجربة إلى DB،

ثانيًا, ، استخدمت الرقم التسلسلي الجهاز لتحديد كل جهاز بشكل فريد،

أخيرا, ، يعتمد التطبيق على القيمة الزمنية التي تم إرجاعها من اتصال الخادم وليس وقته الخاص حتى لا يمكن التحايل للنظام إلا إذا تم تغيير الرقم التسلسلي للجهاز، وهو أمر مرهق للغاية للمستخدم.

حتى هنا يذهب رمزي (للنشاط التجريبي):

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 الخاص بي مثل هذا (تكنولوجيا الراحة النحيفة):

/**
     * 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;
        }

    }

ثم في النشاط الرئيسي، استخدم التفضيل المشترك (INSTERTDATE تم إنشاؤه في نشاط التجربة) لمراقبة عدد الأيام المتبقية وإذا انتهت الأيام، أحظر النشاط الرئيسي لرسالة تأخذها إلى المتجر للشراء.

الجانب الوحيد أسفل أرى هنا هو أنه إذا كان المستخدم المارق للمستخدم يشتري التطبيق المدفوع ويقرر المشاركة مع تطبيقات مثل Zender، مشاركة الملفات أو حتى مضيف ملف APK مباشرة على خادم للناس للتحميل مجانا. ولكن أنا متأكد من أنني سأحدث قريبا هذه الإجابة بحل ذلك أو رابط للحل.

آمل أن ينقذ هذا الروح ... في يوم من الأيام

سعيد الترميز ...

snctln. يمكن إجراء الخيار 3 بسهولة إضافة ملف PHP إلى خادم ويب مع PHP و MySQL المثبتة مثل العديد منها.

من جانب Android، يتم تمرير معرف (معرف الجهاز، حساب Google O ما تريده) كوسيطة في عنوان URL باستخدام httpurlconnection وإرجاع PHP تاريخ التثبيت الأول إذا كان موجودا في الجدول أو إدراج صف جديد و إرجاع التاريخ الحالي.

انه يعمل بشكل جيد بالنسبة لي.

إذا كان لدي وقت سأقوم بنشر بعض الكود!

حظا طيبا وفقك الله !

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top