私はいくつかのSOプログラムで電話を終了する方法について議論した投稿を見ました、例えば これ 。うん、人々は結果に焦点を合わせますが、実際には誰も説明しません理由なぜそれが機能するのですか?
私はコードを試しました、それはうまくいきます。しかし、私はその下で何が起こっているのかについてもっと詳しく知りたいですか? ITelephony.aidlを作成することにより、Android非表示の内部ITelephony
インターフェイスがプロジェクト?私たち自身はどのように作成しましたかITelephony.aidl&自動生成されたJava(/gen/ITelephony.Java)link toAndroidのITelephony
インターフェイス?名前が一致しているためか(パッケージ名とエイドルファイル名)?
TelephonyManager tm = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
Class c = Class.forName(tm.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
//Why does the Android internal ITelephony interface is exposed after created the ITelephony.aidl?
com.Android.internal.telephony.ITelephony telephonyService = (ITelephony) m.invoke(tm);
telephonyService.endCall();
実際には、プロジェクトに_ITelephony.aidl
_を追加する必要はなく、単に便利です。次のようにすることもできます。
_TelephonyManager tm = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
Class c = Class.forName(tm.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
Object telephonyService = m.invoke(tm); // Get the internal ITelephony object
c = Class.forName(telephonyService.getClass().getName()); // Get its class
m = c.getDeclaredMethod("endCall"); // Get the "endCall()" method
m.setAccessible(true); // Make it accessible
m.invoke(telephonyService); // invoke endCall()
_
カバーの下では、これはすべてJavaリフレクションを使用してプライベート(つまり、公開されていない)メソッドにアクセスすることで機能します。オープンソース(つまり、公開されている)Androidソースコードを読むことで、そこにあるメソッドとその機能を理解できます。そこに何があり、何をするのかがわかれば、「隠されている」場合でも、リフレクションを使用してそこに到達できます。
TelephonyManager
クラスは、リモートサービスを使用して実装されます。 TelephonyManager
に何かを要求したい場合は、TelephonyManager
(これは公開されている部分です)のメソッドを呼び出し、内部的にリモートテレフォニーサービスを呼び出して実際に作業を行います。これは、一種の「リモートプロシージャコール」であるAIDLを使用して行われます。リモートサービスは、TelephonyManager
クラスを介して公開されていないことを実行できます。ここでは、getITelephony()
を使用して「リモートプロシージャコール」インターフェースのクライアント側を取得しています。これは、タイプITelephony
のオブジェクトを返します。このクラスには、endCall()
という名前のメソッドがあります。タイプITelephony
のオブジェクトを取得したら、そのClassオブジェクトを取得し、ClassからメソッドendCall()
を取得できます。メソッドを取得したら、アクセス可能にしてから呼び出します。メソッドendCall()
は、リモートプロシージャコールのクライアント側にあります。このメソッドは、テレフォニーマネージャーサービス(リモートサーバーで実行されている)にメッセージを送信し、通話を終了するように要求します。
_ITelephony.aidl
_のソースコードは公開されているため、プロジェクトにソースコードを配置すると、IDEが_ITelephony.Java
_(リモートのクライアント側を含む)を生成します。プロシージャコール)_ITelephony.aidl
_から。そうすれば、それをimport
するだけで、IDEはITelephony
クラスとそのメソッドについて知ることができます。これにより、コンパイラはプロジェクトのコンパイル時に正しいバイトコードを生成できます。このコードをAndroidデバイスで実行する場合は、Androidフレームワークを呼び出してITelephony
オブジェクトを取得し、それを_com.Android.internal.telephony.ITelephony
_にキャストします。それ以降、ITelephony
のJavaコードが、返されたITelephony
オブジェクトの実際のクラス定義と一致する限り、生成された_ITelephony.Java
_を使用してオブジェクトのメソッドとフィールドにアクセスできます。クラス定義が一致しない場合、VMは適切な例外をスローします。
これがあなたの質問に答えてくれることを願っています。あなたがこれについてどれだけ知っているか正確にはわからなかったので、あなたがすでに知っていることについて言及したかもしれません。もしそうなら、それについて申し訳ありません。これが明確でない場合は、理解できないことを正確に示してください。
実際、ITelephony.aidlをプロジェクトに追加する必要はありません。それは単に便利なことです。次のようにすることもできます: 正解