드뎌 1년에 한번밖에 없는 추석 한가위가 찾아왔네요.

 

매년 추석마다 여행을 해외나 국내로 여행을 다녔는데 코로나로 인해 올해 추석은 꼼짝도 못하겠네요.

이제 집에서 일주일을 보낼 방법을 궁리중입니다.

넷플릭스로 정주행할까? 스포츠 채널에서 24시간 살아볼까?

여행도 좋지만 이렇게 방콕해서 즐길 수 있는 걸 찾는것도 여행 못지 않게 재미 있을것 같아요.

 

 

넷플릭스에서 이번에 오리지널 시리즈로 나온 보건교사 안은영도 완전 강추입니다.

정유미 팬이라서 그런지 더욱 몰입하게 되네요.

 

스포츠는 손흥민이 부상 당하는 바람에 ㅠㅠㅠㅠㅠ

황희찬이랑 이강인으로 만족해야 할것 같네요.

 

그럼 이번 추석 잘 지내시고 끝나고 또 인사드릴께요.

'일상' 카테고리의 다른 글

코로나 시국에 은애 방콕놀이~  (0) 2020.09.08

안드로이드에서 광고모듈하면 첫번째로 구글애드몹을 생각하실겁니다.

구글애드몹이나 모바일웹을 이용한 애드센스를 붙이는것만 생각하시는데요.

여기에 Unity Ads를 추가하면 좀 더 풍부하게 광고가 나오게 할 수 있습니다.

 

유니티에서도 안드로이드 가이드를 제공하고 있습니다.

https://unityads.unity3d.com/help/android/integration-guide-android#basic-implementation

 

Integration guide for Android (Java) - Knowledge base

Integration guide for Android (Java) Overview This guide covers basic integration for implementing Unity Ads in your native Android game. If you are an iOS developer using Objective-C, click here. If you are a Unity developer using C#, click here. Click he

unityads.unity3d.com

 

첫번째로 unity-ads.aar 파일을 다운로드 합니다.

https://github.com/Unity-Technologies/unity-ads-android/releases

 

Releases · Unity-Technologies/unity-ads-android

Unity Ads SDK 3.0 for Android. Contribute to Unity-Technologies/unity-ads-android development by creating an account on GitHub.

github.com

 

프로젝트를 우클릭해서 New -> Module 선택합니다.

Import .JAR/.AAR Package를 선택하고 다운로드한 aar 파일을 Import 해줍니다.

 

프로젝트 선택후 우클릭 OpenModule Settings 선택

Dependencies 선택후 + 버튼 클릭후 Module Dependency 선택후 unity-ads 선택

 

이렇게 해서 unity-ads를 사용하는 모듈을 추가하면 build.gradle dependencies에 unity-ads가 추가됩니다.

dependencies {
    implementation project(path: ':unity-ads')
}

 

 

이제 사용할 곳에서 import해서 사용하시면 됩니다.

import com.unity3d.ads.IUnityAdsListener;
import com.unity3d.ads.UnityAds;

 

다음은 Unity Ads SDK를 초기화 합니다.

SDK를 초기화하려면 적절한 플랫폼에 대한 프로젝트의 게임ID를 참조해야 합니다. 

안드로이드앱에서 광고 콜백을 처리하는 IUnityAdsListener 인터페이스를 구현합니다. SDK를 초기화하는 Initialize 메소드에는 이 리스너가 매개 변수로 필요합니다. 

아래는 소스 코드입니다.

 

import com.unity3d.ads.IUnityAdsListener;
import com.unity3d.ads.UnityAds;

public class InitializeAdsScript extends AppCompatActivity implements View.OnClickListener, IUnityAdsListener {

    private String unityGameID = "1234567";
    private Boolean testMode = true;

    @Override
    protected void onCreate (Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        setContentView (R.layout.activity_main);
        // Declare a new listener:
        final UnityAdsListener myAdsListener = new UnityAdsListener ();
        // Add the listener to the SDK:
        UnityAds.addListener(myAdsListener);
        // Initialize the SDK:
        UnityAds.initialize (this, unityGameID, testMode);
    }

    // Implement the IUnityAdsListener interface methods:
    private class UnityAdsListener implements IUnityAdsListener {

        @Override
        public void onUnityAdsReady (String placementId) {
            // Implement functionality for an ad being ready to show.
        }

        @Override
        public void onUnityAdsStart (String placementId) {
            // Implement functionality for a user starting to watch an ad.
        }

        @Override
        public void onUnityAdsFinish (String placementId, UnityAds.FinishState finishState) {
            // Implement functionality for a user finishing an ad.
        }

        @Override
        public void onUnityAdsError (UnityAds.UnityAdsError error, String message) {
            // Implement functionality for a Unity Ads service error occurring.
        }
    }
}

 

전면광고를 표시하려면 게재 위치 ID로 표시 기능을 사용하면 됩니다.

전면광고 예제코드입니다.

import com.unity3d.ads.IUnityAdsListener;
import com.unity3d.ads.UnityAds;

public class ShowInterstitialAds extends AppCompatActivity implements View.OnClickListener, IUnityAdsListener {

    private String unityGameID = "1234567";
    private Boolean testMode = true;
    private String placementId = "video";

    @Override
    protected void onCreate (Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        setContentView (R.layout.activity_main);
        // Declare a new listener:
        final UnityAdsListener myAdsListener = new UnityAdsListener ();
        // Add the listener to the SDK:
        UnityAds.addListener(myAdsListener);
        // Initialize the SDK:
        UnityAds.initialize (this, unityGameID, testMode);
    }

    // Implement a function to display an ad if the Placement is ready:
    public void DisplayInterstitialAd () {
        if (UnityAds.isReady (placementId)) {
            UnityAds.show (this, placementId);
        }
    }

    // Implement the IUnityAdsListener interface methods:
    private class UnityAdsListener implements IUnityAdsListener {

        @Override
        public void onUnityAdsReady (String placementId) {
            // Implement functionality for an ad being ready to show.
        }

        @Override
        public void onUnityAdsStart (String placementId) {
            // Implement functionality for a user starting to watch an ad.
        }

        @Override
        public void onUnityAdsFinish (String placementId, UnityAds.FinishState finishState) {
            // Implement functionality for a user finishing an ad.
        }

        @Override
        public void onUnityAdsError (UnityAds.UnityAdsError error, String message) {
            // Implement functionality for a Unity Ads service error occurring.
        }
    }
}

 

보상형광고도 마찬가지입니다. 광고시청에 대한 보상을 제공하면서 표시되는 광고입니다. 동영상 광고를 완료한 앱사용자에게 보상을 제공하려면 onUnityAdsFinish 리스너 콜백 메소드의 FinishState 결과를 사용하여 사용자가 광고 시청을 완료했는지, 보상을 받아야 하는지 확인합니다.

아래는 보상형 광고 예제 샘플입니다.

import com.unity3d.ads.IUnityAdsListener;
import com.unity3d.ads.UnityAds;

public class ShowRewardedAds extends AppCompatActivity implements View.OnClickListener, IUnityAdsListener {

    private String unityGameID = "1234567";
    private Boolean testMode = true;
    private String placementId = "rewardedVideo";

    @Override
    protected void onCreate (Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        setContentView (R.layout.activity_main);
        // Declare a new listener:
        final UnityAdsListener myAdsListener = new UnityAdsListener ();
        // Add the listener to the SDK:
        UnityAds.addListener(myAdsListener);
        // Initialize the SDK:
        UnityAds.initialize (this, unityGameID, testMode);
    }

    // Implement a function to display an ad if the Placement is ready:
    public void DisplayRewardedVideoAd () {
        if (UnityAds.isReady (placementId)) {
            UnityAds.show (this, placementId);
        }
    }

    // Implement the IUnityAdsListener interface methods:
    private class UnityAdsListener implements IUnityAdsListener {

        public void onUnityAdsReady (String placementId) {
            // Implement functionality for an ad being ready to show.
        }

        @Override
        public void onUnityAdsStart (String placementId) {
            // Implement functionality for a user starting to watch an ad.
        }

        @Override
        public void onUnityAdsFinish (String placementId, UnityAds.FinishState finishState) {
            // Implement conditional logic for each ad completion status:
           if (finishState.equals(UnityAds.FinishState.COMPLETED) {
              // Reward the user for watching the ad to completion.
           } else if (result == FinishState.SKIPPED) {
              // Do not reward the user for skipping the ad.
           } else if (result == FinishState.ERROR) {
              // Log an error.
           }
        }

        @Override
        public void onUnityAdsError (UnityAds.UnityAdsError error, String message) {
            // Implement functionality for a Unity Ads service error occurring.
        }
    }
}

위와 같이 안드로이드에서도 간단하게 유니티 ads 광고를 붙일 수 있습니다.

구글애드몹 광고가 잘 나오지 않을때 효율이 좋지 않을때 유니티 광고와 병행을 한다면 더욱 좋은 결과를 만드실 수 있습니다. 

유니티로 개발하다 보면 여러가지를 손대다 보니 안드로이드로 컴파일 할때 빠뜨리게 되는 부분들이 많이 있습니다. 아래 오류도 그 중에 한가지가 되겠습니다.

 

디버그가 가능한 APK를 업로드했습니다. 보안상의 이유로 Google Play에 게시하기 전에 디버그를 사용 중지해야 합니다. 

1. 오류 내용

 

2. 오류 확인

보통 유니티를 안드로이드 컴파일하게 되면 디버그 모드를 확인할때 2군데를 확인합니다. Project Settings에 컴파일러 환경 부분과 Build Settings에 Development Build부분을 확인해서 디버그 모드인지 릴리즈 모드인지 확인하게 됩니다.

 

 

3. 해결방법 

 

만약 이 두곳이 다 릴리즈로 셋팅되어 있는데도 콘솔 업로드시 위와 같은 오류가 발생한다면 마지막으로 

확인해봐야 할 곳은 Publishing Settings에 Custom Gradle Template가 체크되어 있어서 Gradle 파일을 커스텀하게

사용했을때 mainTemplate.gradle 파일을 확인하는 방법이 있겠습니다.

경로는 Assets\Plugins\Android\mainTemplate.gradle 입니다.

 

mainTemplate.gradle에서 debuggable 속성 부분을 찾아서 true로 되어 있으면

false로 바꾸거나 삭제해주면 됩니다.

코로나로 인해 집구석에 박혀 있는 시간이 많아지다보니

우리 딸래미가 많이 심심했나 봅니다.

 

평상시 유튜브로 라임튜브같은 걸 많이 시청하다보니 

자기도 따라하고 싶었나 봅니다.

 

중간중간 실수도 하고 재미있게 촬영하였습니다.

 

 

 

마리모 키우기로 컨텐츠를 한번 만들어보았습니다.

 

너무 좋아하면서 재밌어 하네요. 

집에서만 있으면 TV나 휴대폰만 보려고 하는데 이렇게 유튜브 컨셉으로 방송을 한번 찍어보는것도 재미있을것 

같습니다.

 

은애야 커서 방송하지말고 의사해~~ ㅋㅋ

 

사랑해 은애야~!

 

'일상' 카테고리의 다른 글

추석 전날 풍경~~~~!  (0) 2020.09.29

유니티를 개발하다보면 엄청나게 많은 종류의 빌드에러를 맞이하게 됩니다.

 

 

이곳저곳 구글링 신에게 도움을 청해보지만 정확한 답을 구하기는 쉽지 않습니다.

 

D8 : Program type already present : com.unity3d.ads.mediation.IUnityAdsExtendedListener

 

에러 내용으로 추측해 보면 UnityAds 관련 모듈이 이미 있다고 나는 에러 같습니다.

 

먼저 프로젝트 부분을 살펴보겠습니다.

 

UnityAds 모듈 부분이 존재하고 있습니다. 

그리고 또 다른 UnityAds부분을 로드하는 Services 탭을 살펴보겠습니다.

위와 같이 Services 탭에 Unity Ads를 Enable 시키고 프로젝트 파일에서도 Unity Ads를 임포트 시켜서

충돌이 일어난 것 같습니다.

 

소스 부분보다 Services 탭에 있는 Unity Ads를 Disable 시켜서 다시 컴파일 하면 정상적으로

완료됩니다.

 

알고 나면 쉬운 부분인데 프로그래밍 작업을 하다보면 이런 사소한 실수로 오랫동안 헤매는 경우가 있습니다.

프로그램 짜는 시간보다 디버깅하는 시간이 더 길어지면 그것보다 비효율적인 일이 어디 있겠습니까?

 

저처럼 헤매지 마시라고 에러 부분 종종 올려드리겠습니다.

 

 

이전 글에서 Navigation Drawer하고 Tabs를 붙이는 예제를 해보았습니다.

디자인적인 부분만 작업하였기 때문에 Tabs나 Navigation Drawer 에 버튼 클릭 부분을

구현해 보도록 하겠습니다. 

 

먼저 MainActivity.java에 Viewpager,Tablayout,Tabitem을 추가하도록 하겠습니다.

 

import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.widget.Toolbar;
import androidx.viewpager2.widget.ViewPager2;

import android.os.Bundle;


import com.google.android.material.navigation.NavigationView;
import com.google.android.material.tabs.TabItem;
import com.google.android.material.tabs.TabLayout;

public class MainActivity extends AppCompatActivity {
    DrawerLayout drawerLayout;
    ActionBarDrawerToggle toggle;
    NavigationView navigationView;
    ViewPager2 pager;
    TabLayout mTabLayout;
    TabItem tab1,tab2,tab3,tab4,tab5;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        pager = findViewById(R.id.viewpager);
        mTabLayout = findViewById(R.id.tablayout);
        tab1 = findViewById(R.id.tab1);
        tab2 = findViewById(R.id.tab2);
        tab3 = findViewById(R.id.tab3);
        tab4 = findViewById(R.id.tab4);
        tab5 = findViewById(R.id.tab5);
        

        drawerLayout = findViewById(R.id.drawer);
        navigationView = findViewById(R.id.nav_view);

        toggle = new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.open,R.string.close);
        drawerLayout.addDrawerListener(toggle);
        toggle.setDrawerIndicatorEnabled(true);
        toggle.syncState();
    }
}

그리고 빈 fragment를 추가합니다.

res->New->Fragment->Fragment(Blank) 빈 fragment를 선택해줍니다.

탭 갯수만큼 만들어주시면 됩니다. 이름도 각 탭에 맞게 만들어주시구요.

그런다음 java 클래스를 하나 추가합니다.

New-> Java Class -> PagerAdapter.java

 

package com.apprichkorea.misstrot;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;


public class PagerAdapter extends FragmentStateAdapter {

    private int tabsNumber;

    public PagerAdapter(@NonNull FragmentManager fm, Lifecycle l, int tabs) {
        super(fm, l);
        this.tabsNumber = tabs;
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        switch (position){
            case 0:
                return new First();
            case 1:
                return new Second();
            case 2:
                return new Three();
            case 3:
                return new Four();
            case 4:
                return new Five();
            default: return null;
        }
    }

    @Override
    public int getItemCount() {
        return tabsNumber;
    }
}

 각 탭을 클릭했을때 이동할 fragment를 생성해서 넘어가게 코딩을 해 줍니다.

 

이제 마지막으로 MainActivity.java에서 이벤트 리스너와 아답터를 연결하는 부분을 코딩해 줍니다.

package com.apprichkorea.misstrot;

import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.FragmentPagerAdapter;

import androidx.viewpager.widget.ViewPager;
import androidx.viewpager2.widget.ViewPager2;

import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

import com.google.android.material.navigation.NavigationView;
import com.google.android.material.tabs.TabItem;
import com.google.android.material.tabs.TabLayout;


public class MainActivity extends AppCompatActivity {
    DrawerLayout drawerLayout;
    ActionBarDrawerToggle toggle;
    NavigationView navigationView;
    ViewPager2 pager;
    TabLayout mTabLayout;
    TabItem tab1,tab2,tab3,tab4,tab5;
    PagerAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        pager = findViewById(R.id.viewpager);
        mTabLayout = findViewById(R.id.tablayout);
        tab1 = findViewById(R.id.tab1);
        tab2 = findViewById(R.id.tab2);
        tab3 = findViewById(R.id.tab3);
        tab4 = findViewById(R.id.tab4);
        tab5 = findViewById(R.id.tab5);

        drawerLayout = findViewById(R.id.drawer);
        navigationView = findViewById(R.id.nav_view);

        toggle = new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.open,R.string.close);
        drawerLayout.addDrawerListener(toggle);
        toggle.setDrawerIndicatorEnabled(true);
        toggle.syncState();

        adapter = new PagerAdapter(getSupportFragmentManager(), getLifecycle(),mTabLayout.getTabCount());
        pager.setAdapter(adapter);

        mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                pager.setCurrentItem(tab.getPosition());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });

        //pager.addOnLayoutChangeListener((View.OnLayoutChangeListener) new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));
    }
}

이렇게 하고 컴파일을 하면 탭바를 누를때마다 다른 fragment화면이 나오게 됩니다.

 

이번 시간에는 안드로이드 앱 개발중에 Navigation Drawer와 Tabs를 같이 사용하려고 할때

만드는 방법에 대해 설명합니다.

 

기본 프로젝트를 생성하면 Navigation Drawer 하고 Tabs는 따로 선택할 수 있게 되어 있습니다.

 

요즘 출시되는 앱들을 보면 Navigation Drawer 하고 Tabs를 혼합한 앱들이 많이 보입니다.

이럴때 같이 붙여서 사용해야 할 때 사용하시면 됩니다.

 

먼저 Empty Activity로 프로젝트를 생성합니다.

 

 

프로젝트를 생성한 다음 res->layout 오른쪽 클릭해서 New Resource File 선택한후에 File name 에 nav_header라고 

네이게이션 헤더 리소스를 추가합니다.

 

Root element는 LinearLayout 으로 변경합니다.

 

마찬가지로 한번더 리소스 추가를 해서 content_main을 추가해 줍니다.

 

content_main.xml 코드를 수정해 줍니다.

toolbar 부분을 지정해 줄껍니다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <androidx.appcompat.widget.Toolbar
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimaryDark"
        android:id="@+id/toolbar"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Design 부분으로 넘어가서 Constraint Widget을 수정해줍니다.

이제 tabs를 붙여줄 차례입니다.

왼쪽 containers -> TabLayout 클릭해서 아래 component Tree에 붙입니다.

TabLayout을 붙이면 상단에 붙어 있습니다. 이걸 아래로 드래그해서 toolbar 아래에 맞게 붙입니다.

그리고 TabLayout도 Constraint Widget을 수정해줍니다. ID도 tablayout으로 정해줍니다.

나머지 tabitem들도 id와 text를 변경해줍니다.

이제 tablayout에서 선택시 보여질 뷰페이지를 추가합니다.

뷰페이지를 추가하고 Constraint Widget을 수정해줍니다.

 

activity_main.xml에서 content_main.xml을 인클루드해서 사용합니다.

코드는 아래와 같습니다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <include
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        layout="@layout/content_main"/>



</androidx.drawerlayout.widget.DrawerLayout>

여기까지 탭뷰부분을 붙여보았습니다. 이제는 Navigation Drawer 부분을 추가해 보겠습니다.

activity_main.xml 디자인에서 Containers -> NavigationView를 추가합니다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:id="@+id/drawer">

    <include
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        layout="@layout/content_main"/>

    <com.google.android.material.navigation.NavigationView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/nav_view"/>


</androidx.drawerlayout.widget.DrawerLayout>

activity_main.xml도 수정해 줍니다.

네비게이션 헤더 부분을 작업할 차례입니다.

nav_header.xml 디자인에서 백그라운드 색상 변경과 TextView 하나를 추가합니다.

헤더부분만 높이를 정합니다.

저는 250dp로 잡았습니다.

메뉴부분을 추가하겠습니다.

res->New Resource File 선택한후에 그림과 같이 셋팅합니다.

메뉴아이템 Menu Itme 1을 추가합니다. 

activity_main.xml에 메뉴추가한 부분을 추가해줍니다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:id="@+id/drawer">

    <include
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        layout="@layout/content_main"/>

    <com.google.android.material.navigation.NavigationView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/nav_view"
        app:menu="@menu/nav_menu"
        app:headerLayout="@layout/nav_header"
        android:fitsSystemWindows="true"
        android:layout_gravity="start"/>


</androidx.drawerlayout.widget.DrawerLayout>

이제 거의 다 왔습니다. MainActivity.java에서 툴바와 네이게이션바를 붙이고 액션 토글이벤트를 추가하면 됩니다.

import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.widget.Toolbar;

import android.os.Bundle;


import com.google.android.material.navigation.NavigationView;

public class MainActivity extends AppCompatActivity {
    DrawerLayout drawerLayout;
    ActionBarDrawerToggle toggle;
    NavigationView navigationView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        drawerLayout = findViewById(R.id.drawer);
        navigationView = findViewById(R.id.nav_view);

        toggle = new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.open,R.string.close);
        drawerLayout.addDrawerListener(toggle);
        toggle.setDrawerIndicatorEnabled(true);
        toggle.syncState();
    }
}

 

컴파일 하고 실행을 해보시면 탭바와 네비게이션이 제대로 작동하시는걸 보실수 있습니다.

 

안녕하세요. 낙타입니다.

 

이번시간에는 Google Adsense Api를 사용하는 방법에 대해서 설명드릴려고 합니다.

Adsense Api에는 여러 기능들이 있는데요.

그중에 제일 많이 사용할 수 있는 일별 수익금액 확인 하는 방법,광고제재등 알림을 받는 방법에 대해서 

PHP로 구현해 보도록 하겠습니다.

 

먼저 구글 API 콘솔로 가보도록 하겠습니다.

콘솔 API에서 API라이브러리로 가서 Adsense Management API를 선택합니다.

 

 

그러면 사용할지 묻는 화면이 나옵니다. 당연히 사용을 클릭합니다.

 

사용 선택을 하고 나면 Adsense Management API 를 사용할 수 있게 셋팅이 된 것입니다.

이제 OAuth 2.0 인증을 위한 사용자 인증 정보를 만들어야 합니다.

그리고 지금 만들고 있는 API설정 계정은 Adsense 승인 받은 계정이 아니라도 상관없습니다.

나중에 토큰생성할때만 Adsense 승인을 받은 계정으로 로그인하면 됩니다.

 

사용자 인증 정보를 만들기 위해 클릭을 합니다.

위와같이 php로 구현할꺼니까 웹 애플리케이션으로 지정하고 이름은 애드센스로 정하시면 됩니다.

아래 승인된 자바스크립트 출처는 API를 사용할 URI를 지정해주시고

승인된 리디렉션 URI는 OAuth 2.0 로그인이 끝난후 Call Back URI 를 적어 주시면 됩니다.

 

만들기를 클릭하면 위 화면과 같이 OAuth 클라이언트가 생성이 됩니다.

이 클라이언트 ID와 클라이언트 보안 비밀번호를 꼭 저장해 놓으세요. 

나중에 API 호출시 필요한 정보입니다.

 

그런 다음 refresh token을 구해야 합니다.

refresh token을 구하려면

developers.google.com/oauthplayground/ oauthplayground로 갑니다.

 

왼쪽에는 API를 선택하는 화면입니다.

여기서는 Adsense Management API v1.4 를 선택하고 아래 scope를 선택하면 됩니다.

https://www.googleapis.com/auth/adsense

https://www.googleapis.com/auth/adsense.readonly

 

그리고 오른쪽에서는 환경설정부분에 Use your own OAuth credentials 체크해주시고

아래 OAuth Client ID, OAuth Client secret 을 적어 줍니다.

이 값은 위에서 구글 API 콘솔에서 얻은 값들을 적어주면 됩니다.

Close로 닫아줍니다.

 

정상적으로 값을 다 적어준후에 닫으면 왼쪽편에 Authorize APIs 버튼이 활성화 됩니다.

클릭을 해줍니다.

 

만약 이 오류가 나타난다면 사용자 인증정보 리디렉션 URI값이 없거나 맞지 않을 경우입니다.

다시 한번 확인해 주시면 됩니다. 이 값들이 정상적으로 다 되어 있으면 다음과 같은 화면이 나옵니다.

 

이 때 애드센스가 정상적으로 진행되고 있는 계정으로 로그인을 하면 됩니다.

정상적으로 로그인이 되면 위 화면이 연속적으로 나옵니다.

끝날때 허용을 클릭하면 다음 화면이 나옵니다.

 

여기에서 Exchange authorization code for tokens 버튼을 클릭하면 refresh token이 보여집니다.

이 화면에 나타나는 refresh_token 값을 저장해 둡니다.

이 값을 가지고 2부에 php에서 API를 호출해 보겠습니다.

 

그럼 여기까지 Adsense Management API를 사용하기 위한 준비과정을 알아보았습니다.

API사용을 위한 셋팅을 하고 refresh token값을 얻는것 까지 해서 프로그래밍을 하기 위한 준비는 끝났습니다.

이제 php에서 api를 어떻게 호출하고 사용하는지 알아보도록 하겠습니다.

 

'기타' 카테고리의 다른 글

Google Ads Api 사용법(3/3)  (0) 2020.08.20
Google Ads Api 사용법(2/3)  (0) 2020.08.19
Google Ads Api 사용법(1/3)  (0) 2020.08.19

앞선 시간에는 유니티의 필수요소인 게임매니저에 대해 설명해 드렸는데요.

글로만 설명을 하다보니 정확하게 와닿지 않으실것 같습니다. 그래서 이번 시간에는 게임매니저 싱글턴 구현 예제를 통해 알아보도록 하겠습니다.

 

GameManager 싱글턴 구현

 

GameManager에서 싱글턴을 구현한 부분을 먼저 살펴보고 다른 부분을 완성하겠습니다.

 

public static GameManger instance;

void Awake(){
	if(instance == null)
    {
    	instance = this;
    }else{
    	Debug.LogWarning("두 개 이상의 게임 매니저가 존재합니다");
        Destroy(gameObject);
    }  
}   

GameManager 스크립트의 최상단에는 싱글턴 오브젝트를 할당하기 위한 static 선언된 GameManager 타입의 변수 instance가 있습니다. Awake() 메서드에서는 현재 오브젝트를 싱글턴 오브젝트로 만들고 instance에 할당하는 작업을 실행합니다. instance는 싱글턴이 될 GameManager 오브젝트가 저장될 변수입니다.

 

static으로 선언된 변수는 모든 오브젝트가 공유하는 단 하나의 변수가 됩니다. 이것을 다르게 생각하면 instance는 프로젝트에서 하나만 존재해야 하는 것입니다.

 

instance에는 GameManager 타입 오브젝트의 참조를 할당할 수 있습니다. 그런데 씬에 GameManager타입의 오브젝트가 100개 존재해도 instance는 메모리에 단 하나만 존재하므로 instance에 할당될 수 있는 GameManager 오브젝트도 단 하나뿐입니다. 

 

즉, 싱글턴이 될 GameManager 오브젝트는 스스로를 instance에 할당합니다. 이 과정은 비어있는 왕좌를 경쟁적으로 차지하려는 과정으로 비유할 수 있습니다.

 

Awake() 메서드의 if문 블록에서는 instance가 비어 있다면 그곳에 자기 자신을 할당합니다.

 

만약 instance의 값이 null이라면 instance에 아직 어떠한 GameMannger 타입의 오브젝트도 할당되지 않은 상태입니다. 따라서 현재 Awake() 메서드를 실행하고 있는 GameManager 오브젝트가 this를 instance에 할당하여 스스로를 instance에 할당합니다. this는 오브젝트가 자기 자신을 가리키는 키워드로서 스스로에 대한 참조값이 출력됩니다.

 

이렇게 instance에 할당된 GameManager 오브젝트는 GameManager.instance로 즉시 접근할 수 있습니다.

 

GameManager 타입의 오브젝트는 씬에 단 하나만 존재해야 합니다. 어떠한 이유로 GameManager 오브젝트가 둘 이상 존재하는 경우 싱글턴이 된 GameManager 오브젝트 하나만 남기고 나머지 GameManager 오브젝트는 모두 파괴해야 합니다. 

 

이어지는 else문 블록은 instance가 null이 아닌 경우에 실행됩니다. 즉, 자신이 아닌 다른 GameManager 오브젝트가 instance에 이미 할당된 경우입니다.

 

이 경우 경고 로그를 출력하고 싱글턴이 될 수 없는 자신의 게임 오브젝트를 Destory() 메서드로 파괴했습니다. 

유니티에서는 UI는 물론 플레이어의 상태에 따라 게임의 전반적인 상태를 관리하는 게임 매니저를 만들어야 합니다.

게임 매니저의 역할은 다음과 같습니다.

 

 - 점수 저장

 - 게임오버 상태 표현

 - 게임오버 되었을때 게임오버 UI 활성화

 - 플레이어의 사망을 감지해 게임오버 처리 실행

 - 점수에 따라 점수 UI 텍스트 갱신

 

 

싱글턴 패턴의 필요성

 

게임매니저처럼 관리자 역할을 하는 오브젝트(예를 들면 파일 매니저,몬스터 매니저,점수매니저등)는 일반적으로 프로그램에 단 하나만 존재해야 합니다.(단일 오브젝트) 그리고 언제 어디서든 즉시 접근 가능해야 합니다.

 

우리가 만들 게임 매니저 또한 이 두 가지 조건을 만족해야 합니다.

 

 

단일 오브젝트

 

점수를 관리하는 점수 매니저가 두 개라고 가정해봅시다. 이 경우 최고 점수도 두 개가 될 수 있습니다. 비논리적입니다.

또 다른 예로 파일에 접근하고 수정하는 파일 매니저가 두 개 있다고 가정해봅시다. 이 경우 두 파일 매니저가 동시에 하나의 파일에 접근하고 수정하면서 에러가 날 수 있습니다. 따라서 파일 매니저는 프로그램에 하나만 있는 것이 좋습니다.

이와 같은 이유로 점수와 UI, 게임상태를 관리하는 게임 매니저 또한 게임에 단 하나만 존재해야 합니다.

 

 

손쉬운 접근

 

매니저라고 불리는 오브젝트들은 보통 프로그램의 특정 영역이 아니라 어느 곳에서도 사용할 수 있는 편의 기능을 제공합니다. 따라서 매니저 오브젝트는 코드 어느 곳에서도 쉽게 접근하여 사용할 수 있도록 구현합니다.

 

우리가 구현할 게임 매니저는 게임오버 상태와 점수를 관리합니다. 게임오버 상태와 점수는 게임의 거의 모든 부분에서 사용됩니다. 따라서 어떤 스크립트에서도 씬에 있는 게임 매니저에 쉽게 접근할 수 있어야 합니다.

 

 

싱글턴을 사용하는 이유

 

정리하면 게임매니저는 아래 두 조건을 만족해야 합니다.

 

 - 어떤 곳에서도 손쉽게 게임 매니저 오브젝트에 접근 가능

 - 게임 매니저 오브젝트는 단 하나만 존재

 

이런 조건에서는 주로 싱글턴이라는 디자인 패턴을 사용합니다.

 

싱글턴 패턴은 '어떤 오브젝트가 프로그램에 단 하나만 존재해야 하며, 어느 곳에서도 쉽게 접근 가능해야 할 때' 사용됩니다. 싱글턴 패턴을 사용하면 게임 매니저가 씬에 단 하나만 있게 하고, 어느 곳에서도 게임 매니저에 즉시 접근할 수 있게 만들 수 있습니다. 

 

+ Recent posts