Android-使用通过请求发送的预定输入浏览USSD菜单

问题描述 投票:2回答:1

我正在计划创建一个Android应用,该应用将自动向USSD菜单发送用户回复。只需单击一个按钮,应用程序就会发送初始代码,然后发送其余菜单输入。

例如,初始编号为* 143#,后接1、1、1和用户PIN。我希望能够自动执行输入顺序,以便用户不必自己输入。

[我知道他们在Android Oreo中使用TelephonyManager实施了USSD回调,Android App可以在其中发送USSD请求,然后读取给出的响应。

我目前正在探索该选项,这是我到目前为止所尝试的。 Heavily lifted from this StackOverflow Question.

interface UssdResultNotifiable {
    void notifyUssdResult(String request, String returnMessage, int resultCode);
}


public class MainActivity extends Activity implements UssdResultNotifiable {

    USSDSessionHandler hdl;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void onUssdSend(View view) {
        hdl = new USSDSessionHandler(MainActivity.this, MainActivity.this);
        hdl.doSession(((EditText) this.findViewById(R.id.ussdText)).getText().toString());
    }

    @Override
    public void notifyUssdResult(final String request, final String returnMessage, final int resultCode) {
        this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, "Request was " + request + "\n response is "
                        + returnMessage + "\n result code is " + resultCode, Toast.LENGTH_LONG).show();

                Log.e(TAG, "ussd result hit! Response is = " + returnMessage);

                hdl.doSession("1");
            }
        });

    }

}

class USSDSessionHandler {

    TelephonyManager tm;
    private UssdResultNotifiable client;
    private Method handleUssdRequest;
    private Object iTelephony;

    USSDSessionHandler(Context parent, UssdResultNotifiable client) {
        this.client = client;
        this.tm = (TelephonyManager) parent.getSystemService(Context.TELEPHONY_SERVICE);
        try {
            this.getUssdRequestMethod();
        } catch (Exception ex) {
            //log
        }

    }

    private void getUssdRequestMethod() throws ClassNotFoundException, NoSuchMethodException,
            InvocationTargetException, IllegalAccessException {
        if (tm != null) {
            Class telephonyManagerClass = Class.forName(tm.getClass().getName());
            if (telephonyManagerClass != null) {
                Method getITelephony = telephonyManagerClass.getDeclaredMethod("getITelephony");
                getITelephony.setAccessible(true);
                this.iTelephony = getITelephony.invoke(tm); // Get the internal ITelephony object
                Method[] methodList = iTelephony.getClass().getMethods();
                this.handleUssdRequest = null;

                for (Method _m : methodList)
                    if (_m.getName().equals("handleUssdRequest")) {
                        handleUssdRequest = _m;
                        break;
                    }
            }
        }
    }

    @android.support.annotation.RequiresApi(api = Build.VERSION_CODES.N)
    public void doSession(String ussdRequest) {
        try {

            if (handleUssdRequest != null) {
                handleUssdRequest.setAccessible(true);
                handleUssdRequest.invoke(iTelephony, SubscriptionManager.getDefaultSubscriptionId(), ussdRequest, new ResultReceiver(new Handler()) {

                    @Override
                    protected void onReceiveResult(int resultCode, Bundle ussdResponse) {
                        Object p = ussdResponse.getParcelable("USSD_RESPONSE");

                        if (p != null) {

                            Method[] methodList = p.getClass().getMethods();
                            for(Method m : methodList){
                                Log.e(TAG, "onReceiveResult: " + m.getName());
                            }
                            try {
                                CharSequence returnMessage = (CharSequence) p.getClass().getMethod("getReturnMessage").invoke(p);
                                CharSequence request = (CharSequence) p.getClass().getMethod("getUssdRequest").invoke(p);
                                USSDSessionHandler.this.client.notifyUssdResult("" + request, "" + returnMessage, resultCode); //they could be null
                            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                    }

                });
            }
        } catch (IllegalAccessException | InvocationTargetException e1) {
            e1.printStackTrace();
        }
    }
}

[您得到的是一个要求用户输入USSD的应用程序,一旦单击“发送”按钮,USSD响应就会通过notifyUssdResult功能上的Toast显示。在相同的功能中,我按顺序发送下一个输入“ 1”。我是否能够再次发送回复至USSD,USSD会将其作为输入并进入下一个菜单。

但是,一旦我发送回复,USSD菜单就会显示在我的设备中,我无法继续进行操作。我无法仅通过我的应用程序浏览USSD菜单,因为USSD菜单会干扰屏幕且不会消失。

有什么我可以追踪的样本吗?

android telephony telephonymanager ussd
1个回答
0
投票

不是您,API损坏了!

Google在Oreo中添加的API仅适用于USSD服务,您可以在开始时拨打整个USSD代码并获取响应,而无需在会话中输入任何内容。他们显然没有意识到,大多数电信公司出于安全原因都阻止了此操作,尤其是在有PIN输入的情况下。即使它看起来是为您概述的情况而设计的,它也不起作用。任何多步骤会话都将返回错误代码,或仅返回错误代码。

我的公司Hover开发了一个Android SDK,该SDK使用可访问性服务来运行多步USSD会话,并使其似乎在您的应用程序中发生。您可以为USSD服务创建配置,触发会话以从您的应用运行,并传入所需的任何运行时变量。用户永远不会看到USSD会话,并且在返回响应时会通知您的应用程序,您可以根据需要对其进行解析。它提供UI来从用户那里获取PIN并保持其安全性,从而使其永远不会在USSD会话之外传输。它适用于Android 4.3及更高版本。

SDK可以自由集成和使用,直到您大规模使用。请参阅我们的docs开始使用。

(公开:我是Hover的CTO)

© www.soinside.com 2019 - 2024. All rights reserved.