Страницы

Поиск по вопросам

понедельник, 16 декабря 2019 г.

Как реализовать платное отключение рекламы с помощью in-app

#java #android #реклама #in_app #встроенная_реклама


Не могу разобраться, как реализовать в приложении платное отключение рекламы с помощью
in-app библиотеки AnjLab?

Внизу приведу пример кода:

1) Встраивание рекламы. Здесь все работает, так что если кому нужно можете пользоваться.

Подключение библиотеки build.gradle

compile 'com.google.android.gms:play-services-ads:9.4.0'


В файле AndroidManifest.xml





В текстовый ресурс String.xml вставляю id рекламного баннера  adMobe  

    ca-app-pub-8911529113562577/1565264629


Вставляю баннер в файл app_bar_main.xml



    
        ...
    
    

    



Файл для отображение рекламного баннера Ads.java

public class Ads {
    // создаем метод для создания баннера
    public static void showBanner(final Activity activity) {

        // создаем баннер, находим его по id
        final AdView banner = (AdView) activity.findViewById(R.id.banner);
        // строит и загружает баннер
        // импорт android.gms.ads
        AdRequest adRequest = new AdRequest.Builder().build();
        banner.loadAd(adRequest);

        // слушатель загрузки баннера
        banner.setAdListener(new AdListener() {
            @Override
            public void onAdLoaded() {
                super.onAdLoaded();
                setupContentViewPadding(activity, banner.getHeight());
            }
        });
    }

    // метод подвигает нижний край экрана, на высоте размера баннера
    public static void setupContentViewPadding(Activity activity, int padding) {
        View view = activity.findViewById(R.id.coordinator);
        view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(),
padding);
    }
}


И наконец код для показа рекламного баннера, вставляю в MainActivity.java

    // внедряем баннер
   Ads.showBanner(this);


Все реклама отображается, но как теперь реализовать платное отключение?
Нашел пример на этом сайте. Ссылка.

2) Отключение рекламы.
Я сделал таким образом, в левом меню создал ссылку на отключение рекламы, на файл
SettingsFrag.java

Код:

public class SettingsFrag extends Fragment implements BillingProcessor.IBillingHandler {

    private boolean adsStatus;    // храним текущий статус отображения рекламы
    private boolean initialize;   // храним готовность к покупкам
    private BillingProcessor bp;  // переменная нашего процессора

    private PreferencesManager prefManager; // класс, который работает с SharedPreferences.
Я для себя решил вынести всю логику отдельно
    private Resources resources;            // для работы с ресурсами. Раз получаем
и постоянно обращаемся
    private ToggleButton tbAdsState;        // кнопка

    Context mContext;
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        this.mContext = context;
        // инициализируем `BillingProcessor`. В документации на `GitHub` сказано,
что для защиты от липовых покупок через приложения типа
        // `freedom` необходимо в конструктор `BillingProcessor`'а передать еще и
свой `MERCHANT_ID`. Где его взять - внизу текущего ответа опишу шаги
        bp = new BillingProcessor(context,
                InAppBillingResources.getRsaKey(), InAppBillingResources.getMerchantId(),
this);

        prefManager = new PreferencesManager(context); // класс, который работает
с `SharedPreferences`
        adsStatus = prefManager.getAdsStatus();        // получаем из `SharedPreferences`
сохраненное состояние рекламы (ВКЛ / ВЫКЛ)
        resources = context.getResources();            // получаем "доступ" к ресурсам
    }

    public static SettingsFrag newInstance() {
        Bundle args = new Bundle();
        SettingsFrag fragment = new SettingsFrag();
        fragment.setArguments(args);
        return fragment;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
        // создаем `View` экрана настроек
        View settView = inflater.inflate(R.layout.frag_sett_screen, container, false);

        // инициализация других полей
        tbAdsState = (ToggleButton) settView.findViewById(R.id.tbAdsState);
        // инициализация других полей

        // вешаем слушателя нажатий по кнопке `ToggleButton`
        tbAdsState.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                // `adsStatus` : getAdsStatus из класса `PreferencesManager`
                // true - enabled (ВКЛ)  | false - disabled (ВЫКЛ)
                if (adsStatus && initialize) {
                    bp.purchase(getActivity(), InAppBillingResources.getSKU_Disable_Ads());
                }

                if (!adsStatus) {
                    tbAdsState.setChecked(false);
                    Toast.makeText(getActivity(),
                            getActivity().getResources().getString(R.string.txt_ads_is_already_disabled),
                            Toast.LENGTH_LONG).show();
                }

            }
        });

        return settView;
    }

    @Override
    public void onResume() {
        super.onResume();
        tbAdsState.setChecked(prefManager.getAdsStatus());
    }

    // диалог, который скажет пользователю, что после покупки необходимо перезагрузиться
    private void restartDialog() {

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle(resources.getString(R.string.msg_notification_Title));
        builder.setCancelable(false);
        builder.setPositiveButton("Ок",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        restartApp();
                        dialog.cancel();
                    }
                }
        );
        AlertDialog resetDialog = builder.create();
        resetDialog.show();

    }

    // перезагружаем приложение
    private void restartApp() {
        Intent rIntent = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName());
        if (rIntent != null) {
            rIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            mContext.startActivity(rIntent);
        }
    }

    // ... другие методы класса
    // [START billing part of class]

    @Override
    public void onProductPurchased(@NonNull String productId, TransactionDetails
details) {
        // Called when requested PRODUCT ID was successfully purchased
        // Вызывается, когда запрашиваемый PRODUCT ID был успешно куплен

        if (bp.isPurchased(productId)) {
            prefManager.setAdsStatus(false); // 1. записываем в `SharedPreferences`
состояние рекламы (ВЫКЛ / false)
            tbAdsState.setChecked(false);    // 2. устанавливаем `TogglButton` в
соответствующее состояние
            restartDialog(); // 3. перезагружаем приложение
        } else {
            tbAdsState.setChecked(true); // иначе, если не прошла покупка, оставляем
состояние (ВКЛ / true)
        }
    }


    @Override
    public void onPurchaseHistoryRestored() {
        //Вызывается, когда история покупки была восстановлена,
        // и список всех принадлежащих идентификаторы продуктов был загружен из Google Play

        // так Вы сможете НУЖНУЮ покупку проверить
        for (String sku : bp.listOwnedProducts()) {
            //MyAppLogs.show("Owned Managed Product: " + sku);
            boolean wasBouhtg = sku.equals(InAppBillingResources.getSKU_Disable_Ads());
            if (wasBouhtg) {
                // true - куплено
                // пишем в `SharedPreferences`, что отключили рекламу
            } else {
                // false - не куплено
                // пишем в `SharedPreferences`, что нужно показывать рекламу
            }
        }
    }

    @Override
    public void onBillingError(int errorCode, Throwable error) {
        // Вызывается, когда появляется ошибка. См. константы класса
        // для получения более подробной информации
    }

    @Override
    public void onBillingInitialized() {
        // Вызывается, когда bp был инициализирован и он готов приобрести
        initialize = true;
    }
    // [END billing part of class]

}


Файл PreferencesManager.java

public class PreferencesManager {

    private static SharedPreferences mSPref;
    private SharedPreferences.Editor mSPEditor;

    private static final String APP_PREF    = "app_pref";      // имя файла настроек
Вашего приложения

    private static final String APP_ADS_STATUS = "adsStatus";  // статус рекламы

    public PreferencesManager(Context context) {
        mSPref = context.getSharedPreferences(APP_PREF, Context.MODE_PRIVATE);
    }

    public void setAdsStatus(boolean adsStatus) {
        // true - enabled  | false - disabled
        mSPEditor = mSPref.edit();
        mSPEditor.putBoolean(APP_ADS_STATUS, adsStatus);
        mSPEditor.apply();
    }

    public boolean getAdsStatus() {
        return mSPref.getBoolean(APP_ADS_STATUS, true);
    }
}


Файл InAppBillingResources.java

public class InAppBillingResources {

    // Ваш `RSA` ключ из `Google Play Developer Console`
    private static final String RSA_KEY = "MAFD.........";
    private static final String MERCHANT_ID = "18.........";           // Ваш `MERCHANT_ID`
из `Google Play Developer Console`
    private static final String SKU_DISABLE_ADS = "android.test.purchased";     
    // Ваш `product_id`, создается в `Google Play Developer Console`


    public static String getRsaKey() {
        return RSA_KEY;
    }

    public static String getMerchantId() {
        return MERCHANT_ID;
    }

    public static String getSKU_Disable_Ads() {
        return SKU_DISABLE_ADS;
    }
}


Файл frag_sett_screen.xml с переключателем.




    




3) Как теперь этот код совместить с отображением рекламы
       Ads.showBanner(this);? 
Что бы если нажать на переключатель или если приложение было уже куплено то скрыть
Ads.showBanner(this); и наоборот если не оплатили, то показывать баннер.

Я понимаю может кому-то этот вопрос покажется глупым, но у меня абсолютно уже мозги
не работают, не могу никак сообразить.
    


Ответы

Ответ 1



На сколько я понял, Ваше приложение работает по схеме в одной Activity показываем Fragmentы. Хорошо. Так как у Вас есть метод, который подымает пользовательский контент и показывает под ним рекламу, то мы его и будем пытаться обуздать :-) Что делаем ? В классе MainActivity (или как там у Вас называется главная Activity) @Override protected void onCreate(Bundle savedInstanceState) { // получаем наши `SharedPreferences` PreferencesManager prefManager = new PreferencesManager(this); super.onCreate(savedInstanceState); setContentView(R.layout.activity_min); // проверяем нашу запись в файле настроек. Если реклама не отключена, то у нас будет true записано, то есть состояние ВКЛЮЧЕНО // а также проверяем подключение к сети Internet простеньким способом // true - enabled | false - disabled boolean adsState = prefManager.getAdsStatus(); if (adsState && CheckURLConnection.isNetworkAvailable(this)) { Ads.showBanner(this, adsState); } else { Ads.showBanner(this, adsState); } // далее Вы просто инициализируете все свои `View` в `MainActivity` // добавляете что нужно } класс CheckURLConnection public class CheckURLConnection { public static boolean isNetworkAvailable(Context context) { ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); return activeNetworkInfo != null; } } класс Ads public class Ads { public static void showBanner(final Activity activity, boolean adsState) { // вместо LinearLayout у Вас будет ВАШ View, который располагается над AdView. В вопросе фигурирует CoordinatorLayout, вот его и нужно будет здесь инициализировать по аналогии с LinearLayout final LinearLayout adsContainer = (LinearLayout) activity.findViewById(R.id.container); final AdView mAdView = (AdView) activity.findViewById(R.id.banner); if (adsState) { AdRequest adRequest; // DEBUG or RELEASE if (BuildConfig.DEBUG) { adRequest = new AdRequest.Builder() .addTestDevice() .build(); } else { adRequest = new AdRequest.Builder() .build(); } mAdView.loadAd(adRequest); mAdView.setAdListener(new AdListener() { @Override public void onAdLoaded() { super.onAdLoaded(); setupContentViewPadding(activity, mAdView.getHeight()); } }); } else { adsContainer.removeView(mAdView); } } public static void setupContentViewPadding(Activity activity, int padding) { View view = activity.findViewById(R.id.container); // рекомендую добавить 8dp отступа над баннером, чтобы была ЧЕТКАЯ граница, которая отделяет его и пользовательские данные (Google просто рекомендует делать границу, иначе могут быть ложные клики и бан AdMob аккаунта) view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), padding + 8); } } <здесь Hash Вашего смартфона или эмулятора> [тип String] - нужно делать для того, чтобы в режиме отладки приложения (DEBUG) Вы сами себе не испортили всё! То есть не стали показывать сами себе настоящую рекламу, проверять клики по ней. Проверка - это нормально! Но не нормально проверять на реальный баннерах, за что Google/AdMob банит аккаунт AdSense. Когда соберете приложение (выпустите его в Google Play Маркет), то будет выполняться блок else условия if (BuildConfig.DEBUG) В итоге мы получаем: - в MainActivity происходит проверка состояния adsState из наших локальных настроек PreferencesManager, а также проверка доступа в сеть Internet. Если куплено отключение рекламы, то метод getAdsStatus() вернет нам false. И реклама не будет показана. - как производить покупку отключения рекламы я описал здесь (https://ru.stackoverflow.com/a/770241/22239). Там и про ToggleButton есть, и про ее обновление, и диалоги с пользователем. Пишите в комментарии, если будут вопросы. Успехов! ;-) // Увы, но весь код приложения за Вас я написать не могу. Ваш вопрос не глупый! По природе вопросов глупых нет, есть люди, которые полностью в чем-то не разобрались/изучили. // Кстати, Вы мне мой же код в вопросе прислали. Изучите его хорошо. Я постарался все покрыть комментариями, чтобы было понятно каждому, что происходит на той или иной строчке класса

Комментариев нет:

Отправить комментарий