電話を妨げることができるネイティブのAndroidアプリを作る方法



もともと公開my blog .

TLドクター


このポストでは、私はあなたを呼び出してから特定の番号をブロックすることができますネイティブのAndroidアプリを作る方法を一歩一歩示します.
ソースコードはon Github .
私は、私がここにあなたを示すつもりであるステップガイドによる私のステップがあなたを助けて、さらなる研究をすることからあなたを救うことを望みます.
もちろん、私はその日の仕事でネイティブのAndroid開発者ではないので、私はまた、それは私が再び同じような状況に対処する必要があるときの良いリマインダとして私に役立つという事実のためにそれをやっている.あなたの残りの部分に叫ぶ💪
また、上記の言私は、このコードについてどんなフィードバックも評価します.🙏

!TLドクター


私は、この解決策を捜してStackOveroverflowとブログ柱を通って行く多くの時間を過ごしました.これらのうち、これらは役に立ちました.
  • How to detect incoming calls on an Android device?
  • Can't answer incoming call in android marshmallow 6.0
  • Android permission doesn't work even if I have declared it
  • End incoming call programmatically
  • Is the phone ringing
  • しかし、悲しいことに、それらのどれも簡単な、初心者のチュートリアルの種類だった.それで、たくさんの追加研究の後、私はそれを働かせました、そして、ここでは、方法を説明することにおける私の最善の試みです.

    As a sidenote: while testing this, the discovery of how to simulate an incoming call or SMS to an emulator in Android Studio was also very helpful.


    新しいプロジェクトの開始


    アンドロイド・スタジオFile->New->New Project , それは名前と場所をクリックして与えるNext :

    最小APIレベルのデフォルトオプションを残します

    選択Empty Activity テンプレート

    アクティビティーの名前をそのままにします.

    アンドロイドマニフェスト.XML


    許可を設定するuses-permission )とreceiver タグAndroidManifest.xml ファイル
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.nikola.callblockingtestdemo">
    
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.CALL_PHONE" />
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <receiver  android:name=".IncomingCallReceiver" android:enabled="true" android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.PHONE_STATE" />
                </intent-filter>
            </receiver>
        </application>
    </manifest>
    
    READ_PHONE_STATE 我々がこれを得る許可official docs ):

    Allows read-only access to phone state, including the phone number of the device, current cellular network information, the status of any ongoing calls, and a list of any PhoneAccounts registered on the device.


    CALL_PHONE 我々がこれを得る許可official docs ):

    Allows an application to initiate a phone call without going through the Dialer user interface for the user to confirm the call.


    ⚠️ 私は、ここで述べられていなくても、この許可を必要としているので、プログラムを呼び出して終了することができます.
    The receiver タグは、android.intent.action.PHONE_STATE . AndroidのOSは、この動作を放送するときに、名前のように、電話の変更の状態(私たちは、コールを呼び出し、呼び出しを拒否し、呼び出しなど)です.

    を返します。ジャバ


    新しいクラスを作成するFile->New->Java Class ), それを呼び出すIncomingCallReceiver そして、このコードをペーストしてくださいpackage 名前は私のとは違います!)):
    package com.example.nikola.callblockingtestdemo;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.telephony.TelephonyManager;
    import android.widget.Toast;
    import java.lang.reflect.Method;
    import com.android.internal.telephony.ITelephony;
    
    public class IncomingCallReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
    
            ITelephony telephonyService;
            try {
                String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
                String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
    
                if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING)){
                    TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
                    try {
                        Method m = tm.getClass().getDeclaredMethod("getITelephony");
    
                        m.setAccessible(true);
                        telephonyService = (ITelephony) m.invoke(tm);
    
                        if ((number != null)) {
                            telephonyService.endCall();
                            Toast.makeText(context, "Ending the call from: " + number, Toast.LENGTH_SHORT).show();
                        }
    
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
    
                    Toast.makeText(context, "Ring " + number, Toast.LENGTH_SHORT).show();
    
                }
                if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_OFFHOOK)){
                    Toast.makeText(context, "Answered " + number, Toast.LENGTH_SHORT).show();
                }
                if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)){
                    Toast.makeText(context, "Idle "+ number, Toast.LENGTH_SHORT).show();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    Androidでは、我々は'から取得したいデータをBroadcastReceiver , 我々はそれを継承する必要があるBroadcastReceiver クラスをオーバーライドする必要がありますonReceive メソッド.このメソッドでは、TelephonyManager 呼び出しの状態を取得し、ITelephony 呼び出しを終了するインターフェイスです.
    正直に言うと、これはそれを取得するには少し奇妙な取得するところですITelephony インターフェイスを作成する必要がありますITelephony インターフェイス.

    iTelephonyジャバ


    これを行うには、新しいクラスを作成します.File->New->Java Class ), それを呼び出すITelephony そして、このコードをペーストします(注:以下の内容ですべてを上書きします.はい、奇妙なパッケージ名でも).
    package com.android.internal.telephony;
    
    public interface ITelephony {
        boolean endCall();
        void answerRingingCall();
        void silenceRinger();
    }
    
    アンドロイドスタジオpackage com.android.internal.telephony; (このパッケージの名前の下には赤いドットがあります).私は、これが含まれなければならない理由についての正確な説明を見つけませんでした、それで、あなたが知っているならば、コメントでそれを共有してください.

    実行時のアクセス許可のリクエスト


    これは、仕事にこれを得ることにおける私の成功を妨げていた1つのものでした!
    つまり、Android 6.0 +の後にAndroidManifest.xml ファイルには、危険なアクセス許可のカテゴリに該当する場合は、ユーザーに対して明示的に問い合わせを行う必要があります.以下はこのような権限のリストです.
  • AccessCountの粗い場所
  • アクセッサルズ
  • ボイスメール
  • ボディセンサー
  • 携帯電話
  • カメラ
  • GetCountアカウント
  • <小野寺>
  • ログレスログ
  • Readchen Cellchen放送
  • コンタクトアドレス
  • ReadCal外部ストレージ
  • ドキドキ
  • readsms SMS
  • 領有権
  • 領収書SMS
  • プッシュプルプッシュ
  • オーディオオーディオ
  • センドストラSMS
  • 用法
  • ログレスログ
  • 連絡先
  • 記憶装置
  • このような許可を求めるには、ここで使用するコードがありますMainActivity.javaonCreate )
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_DENIED || checkSelfPermission(Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_DENIED) {
            String[] permissions = {Manifest.permission.READ_PHONE_STATE, Manifest.permission.CALL_PHONE};
            requestPermissions(permissions, PERMISSION_REQUEST_READ_PHONE_STATE);
        }
    }
    
    The PERMISSION_REQUEST_READ_PHONE_STATE 変数は、onRequestPermissionsResult メソッド.もちろん、ユーザーが許可を承認したかどうかによってロジックを実行する必要がない場合は、このメソッドを除外できます.
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case PERMISSION_REQUEST_READ_PHONE_STATE: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "Permission granted: " + PERMISSION_REQUEST_READ_PHONE_STATE, Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(this, "Permission NOT granted: " + PERMISSION_REQUEST_READ_PHONE_STATE, Toast.LENGTH_SHORT).show();
                }
    
                return;
            }
        }
    }
    

    アクションでアプリ


    これは、アプリでは、エミュレータと呼び出しを使用してトリガされたテストで動作している方法ですAndroid Device Monitor アンドロイドスタジオ

    結論


    このポストでは、私はあなたを呼び出すから特定の番号をブロックすることができますネイティブのAndroidアプリを作る方法を示した.私は、私が直面していたブロッカーを指摘しました、そして、私はまだ呼び出しが拒絶される前に、まだ簡単に2番目のために現れるネイティブの着信呼び出しポップアップを隠す解決を捜しています.
    だから、もし何かアイデアを持って、私は提案を開いている💪