Android

4개월만에 찾아온 시련!! 앱이 Google Play 정책을 준수하지 않음

앱이 구글플레이 스토어에서 삭제되었다는 메일을 받았습니다. 4개월 전에 찾아왔던 동일한 문제로 또 다른 앱에서 찾아왔네요. 그래서 그런걸까요? 언제부터인지 하루하루가 불안합니다. 이메일 알림 소리만 들으면 걱정부터 앞서기 시작했어요. 그리고 메일을 확인했을 때 Google Play Support에서 온 메일이 아니면 안심을 하게되었는데… 보란듯이 어제와 오늘 연속 2번의 메일이 왔고, 두 개의 앱이 동일한 이유로 앱이 삭제되었습니다.

삭제 된 앱은 앱의 하단에 광고배너가 존재할 뿐 그 어떤 광고 사기를 조장하는 코드는 없습니다.  

 

특이한 점은 3월 24일에 삭제된 앱 3개에서 비정상적종료 발생이 평소에 비해 300%가 넘게 증가했다는 것입니다.

누군가의 악의적인 공격인지, 아니면 구글AI의 소행인지는 알 수 가 없네요.

 

메일 제목

조치필요 : 앱이 Google Play 정책을 준수하지 않음

 

위반사항

광고 사기를 조장하는 코드가 앱에 포함되어 있습니다.

해당하는 버전 : APK:24

 


아직 해결책을 찾지 못한 상황이고, 구글 정책 지원팀에 문의를 해두었습니다. 왜냐하면 정책을 위반하지 않았기 때문입니다.  빠른 원인 해결을 위해 적어도 문제를 인지한 Class정도는 개발자에게 제공되어야할텐데.. 아무런 내용이 없어요.

그냥 위에 캡쳐한 메일 내용이 전부랍니다. 

 

구글은 기기를 악성 애플리케이션으로부터 보호하기 위해
‘구글 플레이 프로텍트’를 활용합니다. 
이는 기기 내 보호 및 클라우드 기반 머신 러닝 인프라를 통해 
사람이 직접 감독하지 않아도 정기적으로 앱을 스캔하고, 
악성 앱을 빠르게 탐지하는 작업을 통해 기기를 보호합니다. 

 

원인을 알 수 없으니, 어제에 이어 오늘도 삽질중이네요. 이것 저것 만져보고 있어요.  광고 사기 정책도 다시 한 번 보고 정말 광고 사기의 일반 사례에 해당하는지도 한 번 더 살펴보고 있어요. 하지만 해결책은 보이지 않네요.

 

혹시 저와 동일한 원인으로 앱이 삭제된 개발자분들 계신가요?

 

 

2021년에 사기정책이 추가된 듯한데…. 나와 같은 상화에 맞이했던 개발자들도 있었네요

stackoverflow.com/questions/65358952/dont-update-app-fix-the-policy-violation-with-your-app

 

Don’t update app: Fix the policy violation with your app

The application worked fine for half a year, I tried to upload an update, everything was as usual, but the console received “We have determined your app contains code to facilitate Ad Fraud&qu…

stackoverflow.com

구글 고객지원팀에 이의제기를 하였고, 답변메일이 왔네요. 항상 원론적인 답변의 메일만 오는 것에 대한 아쉬움이 남네요. 결국 원론적인 내용을 다시 살펴보고 대응 방법을 살펴보고 있어요.


 

문제해결을 위한 조치

1. 라이브러리 버전 업처리

build.gradle파일 build:gradle의 버전은 3.3.3 이상이면 문제가 없는 것으로 보입니다.

classpath 'com.android.tools.build:gradle:3.3.3'
classpath 'com.google.gms:google-services:4.2.0' 

 

build.gradle파일(app) 버전 상향 처리 : admob관련 라이브러리는 최신버전으로 상향처리했어요,

    implementation 'com.google.android.material:material:1.3.0'
    implementation 'com.google.firebase:firebase-messaging:21.0.1'
    implementation 'com.google.firebase:firebase-core:18.0.2'
    implementation 'com.google.firebase:firebase-ads:19.8.0'

2.화면 레이아웃의 광고 사이즈 변경 ( SMART_BANNER 제거)  : 스마트배너를 지원 더 이상 지원하지 않는 다는 정보가 있어서 스마트 배너를 제거했고, 기본 배너를 호출했거나 적응형배너로 변경하였어요.

        <com.google.android.gms.ads.AdView
            android:id="@+id/adView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            ads:adSize="BANNER"
            ads:adUnitId="@string/banner_ad_unit_id">
        </com.google.android.gms.ads.AdView>

3. 앱 내에 개인정보 처리방침 링크 추가 ( 구글 플레이에 등록한 개인정보 처리방침 링크 사용)

 

4. 광고라이브러리 상향에 따른 광고 코드 초기화 방법변경

as is
MobileAds.initialize(MainActivity.this, getString(R.string.banner_ad_unit_id));

to-be
MobileAds.initialize(this, new OnInitializationCompleteListener() {
  @Override
  public void onInitializationComplete(InitializationStatus initializationStatus) {}
});

 

5. 프로젝트 내 함수들 중에 deprecated 된 함수들 모두 제거!!

제거한 코드 
Environment.getExternalStorageDirectory().getAbsolutePath()

((WifiManager) context.getSystemService(Context.WIFI_SERVICE)).setWifiEnabled(false);

NetworkInfo activeNetwork = dataManager.getActiveNetworkInfo();

.......이하 생략

 

6. 프로젝트 내에 미사용 코드 모두 제거

7. 새로고침 형식의 광고 호출방식 제거

가령 아래와 같은 방법은 새로고침이 될 수 있어요.

A화면에서 B화면 이동시, A화면을 finish()처리 후 B화면으로 이동한다.
그리고 다시 B화면에서 A화면으로 이동시 B화면을 finish()처리후 A화면을 다시 호출한다.

B화면에서 A화면으로 다시 이동해야하는 경우라면 A화면은 finish()처리 하지 않는다.

전제조건으로 A화면에 광고가 있다!!

 

 

코로나 터지기 전에는 앱 올리면 정책위반했을 경우 빠르면 20분 이내로 자동 메일이 와서 바로 다시 수정작업을 할 수 있었는데 지금은 하루가 걸리네요. 3일간의 삽질 끝에 드디어 하루가 지났음에도 위반정책 메일이 오고 있지않아요.

잘 처리된 것일까요? 아니면 주말이라?????

 

어제까지 총 3개의 앱이 동일한 이유로 삭제되었어요.

 

좋은 결과를 기다리며……..바이~~~

<2021.04.05 추가>

기대와 달리 앱 동일한 정책 위반메일이 월요일에 왔다. 주말에는 AI도 쉬나요??

이제 무엇을 어디서 부터 수정해야할지 모르겠네요.

앱 내의 여러개의 광고들 중에서 광고를 하나씩 제거 후 마켓에 등록해보고 있습니다. 

 

<2021.04.06 추가>

구글플레이 스토어등록에 실패했습니다. 앱 내의 광고 개수의 문제가 아닌 것 같네요.

1. 이번에는 백그라운드 서비스에서 activity 호출 방식을 조금 변경해봅니다.

 

AS-IS

메인액티비티클래스(광고 있음)를 호출 후  메인액티비티 클래스에 B화면(광고 없음)을 호출

Intent sIntent = new Intent(context, MainActivity.class);
sIntent.putExtra("action", "start");
sIntent.putExtra("ratio", ratio);
sIntent.putExtra("NOTIFICATION_ID", NOTIFICATION_ID);
sIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);  
sIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 

TO-BE

메인액티비티클래스(광고있음)를 거치지 않고 다이렉트로 B화면(광고 없음)을 호출하도록 변경

Intent sIntent = new Intent(context, SecondActivity.class);
sIntent.putExtra("action", "start");
sIntent.putExtra("ratio", ratio);
sIntent.putExtra("NOTIFICATION_ID", NOTIFICATION_ID);
sIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);  
sIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 

 

2. 앱 내에 존재하는 광고에 대해 모두 적응형 배너로 모두 변경 하였어요(권장되는 배너 광고 구현 사례)

적응형 배너로 바꾸면서 xml레이아웃에서는 패딩값을 주어서 위아래 특정 색상의 라인이 생기도록 처리했어요

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/adb_layout"
        android:layout_marginTop="3dp"
        android:layout_marginBottom="3dp"
        android:paddingTop="10dp"
        android:paddingBottom="10dp"
        android:background="@color/colorxml_color_31"
        android:gravity="center">

        <FrameLayout
            android:id="@+id/ad_view_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"/>
    </RelativeLayout>

3. admob라이브러리 최신버전으로 업데이트

implementation 'com.google.firebase:firebase-ads:20.0.0'

 

4. 백버튼 클릭시 앱이 바로 종료되지않고 사용자에게 되묻기 위해서 다이얼로그 창을 호출했어요.(광고는 없음)

앱 종료 후 광고 노출된다는 어처구니 없는 원론적인 메일 답변에 대한 해결방법(?)이 될지 모르겠네요. 전면 광고가 없음에도 원론적인 내용만 메일로 받아서 참 안타까워요.

     @Override
    public void onBackPressed() {
    
		Dialog exitDialog = new Dialog(MainActivity.this);
        exitDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        exitDialog.setContentView(R.layout.dialog_exit_view);
        if(exitDialog.getWindow()!=null)
            exitDialog.getWindow().setBackgroundDrawable(new ColorDrawable(0)); 
            
        LinearLayout linearLayout3 = exitDialog.findViewById(R.id.linearLayout3);
        linearLayout3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (v.getId() == R.id.linearLayout3) {
                    if (!MainActivity.this.isFinishing() && exitDialog != null && exitDialog.isShowing()) {
                        exitDialog.dismiss();
                    }
                }
            }
        });

        LinearLayout linearLayout4 = exitDialog.findViewById(R.id.linearLayout4);
        linearLayout4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (v.getId() == R.id.linearLayout4) {
                    if (!MainActivity.this.isFinishing() && exitDialog != null && exitDialog.isShowing()) {
                        exitDialog.dismiss();
                    }
                    myExit();
                }
            }
        });
        if (!MainActivity.this.isFinishing()) {
            exitDialog.show();
        }     
    }        
            

 

5. 백그라운드 서비스에서 onTaskRemoved() 오버라이드 코드 제거

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        //Log.e("TAG : ", "===================================");
        //Log.d("TAG : ", "TASK REMOVED");
        //Log.e("TAG : ", "===================================");
        this.regisiterReceiver();
        alarmManagerSetting(this,"onTaskRemoved");
        
        super.onTaskRemoved(rootIntent);        

    }

 

6. 레이아웃 xml내에 광고를 제거한 경우, xmlins:ads 태그 제거

xmlns:ads="http://schemas.android.com/apk/res-auto" 

 

7. proguard-rules.pro 파일에 광고 관련건 추가

# The following rules are used to strip any non essential Google Play Services classes and method.

# For Google Play Services
-keep public class com.google.android.gms.ads.**{
   public *;
}

# For old ads classes
-keep public class com.google.ads.**{
   public *;
}

# For mediation
-keepattributes *Annotation*

# Other required classes for Google Play Services
# Read more at http://developer.android.com/google/play-services/setup.html
-keep class * extends java.util.ListResourceBundle {
   protected Object[][] getContents();
}

-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
   public static final *** NULL;
}

-keepnames @com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
   @com.google.android.gms.common.annotation.KeepName *;
}

-keepnames class * implements android.os.Parcelable {
   public static final ** CREATOR;
}

 

<2021.04.07 추가>

삭제되었던 앱이 모두 마켓에 등록되었습니다. 정확한 원인은 저도 모르겠네요. 백그라운드 서비스에서 액티비티 호출하는 방법을 변경한 부분과 AdMob의 광고 라이브러리 업데이트가 마켓등록의 시발점이 된 것은 아닌가 생각을 해봅니다.

 

Leave a Reply

error: Content is protected !!