[Phần 1] Kết nối máy in Pos với điện thoại Android qua Bluetooth

Xin chào mọi người, chúc mọi người cuối tuần vui vẻ!
Hôm nay mình có thời gian rảnh với lại cũng vừa nghiên cứu xong phần kết nối Android với máy in qua Bluetooth nên tiện đây chia sẻ cho mọi người luôn.
Project mình làm giưới đây do mình tổng hợp từ nhiều nguồn khác nhau (chủ yếu các trang nước ngoài) về sàng lọc thành một module cũng khá hoàn chỉnh, nếu ai cần đi chuyên sâu thì có thể lấy về phát triển thêm.
- Module trong phần 1 này có thể kết nối với hầu hết các loại máy in Pos hiện nay, còn một số con đặc thù phải dùng thư viện riêng mình sẽ hướng dẫn ở phần tiếp theo :) các bạn chờ nhé

- Các chức năng yêu cầu:
  1. Có thể bật bluetooth nếu phát hiện bluetooth chưa bật
  2. Quét ra các thiết bị đã từng kết nối, chọn vào máy in thì tự động kết nối
  3. Quét ra các thiết bị chưa kết nối bao giờ, chọn vào máy in nào thì tự động kết nối
- Lưu ý: các chức năng trên đều diễn ra trong ứng dụng, người dùng không phải thao tác trong phần cài đặt bluetooth
1. Xin cấp các quyền cần thiết trong AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- Đối với Android từ 6.0 trở lên phải xin cấp quyền bằng code:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    mPermissionLocation = false;
    if (requestCode == 1) {
        if (grantResults.length > 0) {
            for (int i = 0; i < grantResults.length; i++) {
                if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                    mPermissionLocation = false;
                    Toast.makeText(this, "Cấp quyền thất bại", Toast.LENGTH_SHORT).show();
                    return;
                }
            }
            mPermissionLocation = true;
            Toast.makeText(this, "Cấp quyền thành công", Toast.LENGTH_SHORT).show();
        }
    }
}

public void initPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        String[] permissions = {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION};

        if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            if (this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                mPermissionLocation = true;
            } else {
                requestPermissions(permissions, 1);
            }
        } else {
            requestPermissions(permissions, 1);
        }
    } else        mPermissionLocation = true;
}
2. Layout activity_main.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    xmlns:card_view="http://schemas.android.com/apk/res-auto"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context=".MainActivity">

    <LinearLayout        android:id="@+id/layout_content"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:orientation="vertical">
        <TextView            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_margin="10dp"            android:textSize="20sp"            android:text="Enter Your Message : " />

        <EditText            android:id="@+id/txtMessage"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_margin="10dp"            android:lines="4"            android:gravity="top"            android:hint="Print text" />

        <Button            android:id="@+id/Scan"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_marginTop="10dp"            android:text="Scan"></Button>

        <Button            android:id="@+id/btnPrint"            android:layout_width="300dp"            android:layout_height="wrap_content"            android:layout_marginTop="5dip"            android:textColor="#fff"            android:layout_gravity="center"            android:layout_centerHorizontal="true"            android:text="Print" />
        <Button            android:id="@+id/btnBill"            android:layout_width="300dp"            android:layout_height="wrap_content"            android:layout_marginTop="5dip"            android:layout_gravity="center"            android:textColor="#fff"            android:layout_centerHorizontal="true"            android:text="Print Bill" />
    </LinearLayout>
</RelativeLayout>

3. MainActivity
- Chuyển đến màn hình quét các thiết bị
btnScan.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter == null) {
            Toast.makeText(MainActivity.this, "Bluetooth not supported!!", Toast.LENGTH_SHORT).show();
        } else {
            //nếu chưa bật bluetooth thì gọi activity bật bluetooth            if (!mBluetoothAdapter.isEnabled()) {
                Intent enableBtIntent = new Intent(
                        BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent,
                        REQUEST_ENABLE_BT);
            } else {
                //ngược lại thì chuyển đến activity quét các thiết bị                Intent connectIntent = new Intent(MainActivity.this,
                        DeviceListActivity.class);
                startActivityForResult(connectIntent,
                        REQUEST_CONNECT_DEVICE);
            }
        }
    }
});
- Sau khi chọn thiết bị kết nối ở bên DeviceListActivity sẽ gọi đến onActivityResult Để kết nối máy in thông qua địa chỉ MAC
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
        case REQUEST_CONNECT_DEVICE:
            if (resultCode == Activity.RESULT_OK) {
                Bundle mExtra = data.getExtras();
                String mDeviceAddress = mExtra.getString("DeviceAddress");
                Log.e(TAG, "Device_Address " + mDeviceAddress);
                mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(mDeviceAddress);

                //UUID MY_UUID = mBluetoothDevice.getUuids()[0].getUuid();                UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

                try {
                    bluetoothSocket = mBluetoothDevice.createInsecureRfcommSocketToServiceRecord(MY_UUID);
                    //bluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(MY_UUID);                    bluetoothSocket.connect();
                } catch (IOException eConnectException) {
                    Log.d(TAG, "CouldNotConnectToSocket", eConnectException);
                    try {
                        bluetoothSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            break;
    }
}
- Print sau khi đã kết nối thành công
protected void printDemo() {
    if (mBluetoothAdapter != null && bluetoothSocket != null) {
        if (bluetoothSocket.isConnected()) {
            try {
                if (outputStream == null)
                    outputStream = bluetoothSocket.getOutputStream();

                byte[] printformat = {0x1B, 0 * 21, FONT_TYPE};
                //outputStream.write(printformat);
                //print title                printUnicode();
                //print normal text                printCustom(message.getText().toString(), 0, 0);
                //printPhoto(R.drawable.img);                printNewLine();
                printText("     >>>>   Thank you  <<<<     "); // total 32 char in a single line                //resetPrint(); //reset printer                printUnicode();
                printNewLine();
                printNewLine();

                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    } else        Toast.makeText(getApplicationContext(), "mBluetoothAdapter or bluetoothSocket is null", Toast.LENGTH_SHORT).show();
}
4. DeviceListActivity
- Bắt đầu tìm kiếm thiết bị
private void initDevicesList() {
    flushData();

    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (mBluetoothAdapter == null) {
        Toast.makeText(getApplicationContext(), "Bluetooth not supported!!", Toast.LENGTH_LONG).show();
        return;
    }

    if (mBluetoothAdapter.isDiscovering()) {
        mBluetoothAdapter.cancelDiscovery();
    }
    // bắt đầu tìm kiếm    mBluetoothAdapter.startDiscovery();

    //Đăng ký broadcasts quét thiết bị mới    IntentFilter filterDiscoverability = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    registerReceiver(broadcastReceiverDiscoverability, filterDiscoverability);

    //Đăng ký broadcasts khi kết nối đến một thiết bị    IntentFilter filterConnect = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
    registerReceiver(broadcastReceiverConnect, filterConnect);

    Toast.makeText(getApplicationContext(), "Getting all available Bluetooth Devices", Toast.LENGTH_SHORT).show();
}
- Quét các thiết bị đã từng kết nối:
//Thiết bị đã kết nốipairedDeviceAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
ListView mPairedListView = findViewById(R.id.paired_devices);
mPairedListView.setAdapter(pairedDeviceAdapter);
mPairedListView.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
        if (mBluetoothAdapter == null)
            return;

        if (mBluetoothAdapter.isDiscovering())
            mBluetoothAdapter.cancelDiscovery();

        String mDeviceInfo = ((TextView) view).getText().toString();
        String mDeviceAddress = mDeviceInfo.substring(mDeviceInfo.length() - 17);
        callActivityResult(mDeviceAddress);
    }
});

//add thiết bị đã kết nốiSet<BluetoothDevice> mPairedDevices = mBluetoothAdapter.getBondedDevices();//get thiết bị đã từng kết nốiif (mPairedDevices.size() > 0) {
    findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
    for (BluetoothDevice mDevice : mPairedDevices) {
        pairedDeviceAdapter.add(mDevice.getName() + "\n" + mDevice.getAddress());
    }
} else {
    String mNoDevices = "Không tìm thấy thiết bị nào";
    pairedDeviceAdapter.add(mNoDevices);
}
- Quét các thiết mới:
newDeviceAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
ListView newDeviceListView = (ListView) findViewById(R.id.listView);
newDeviceListView.setAdapter(newDeviceAdapter);
newDeviceListView.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
        if (mBluetoothAdapter == null) {
            return;
        }

        if (mBluetoothAdapter.isDiscovering()) {
            mBluetoothAdapter.cancelDiscovery();
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            //gọi broadcasts kết nối thiết bị            newBluetoothDevices.getItem(position).createBond();
        }

        Toast.makeText(getApplicationContext(), "Connecting to " + newBluetoothDevices.getItem(position).getName() + "," + newBluetoothDevices.getItem(position).getAddress(), Toast.LENGTH_SHORT).show();
    }
});
- Gọi về MainActivity sau khi lấy được địa chỉ MAC:
void callActivityResult(String address) {
    Bundle mBundle = new Bundle();
    mBundle.putString("DeviceAddress", address);
    Intent mBackIntent = new Intent();
    mBackIntent.putExtras(mBundle);
    setResult(Activity.RESULT_OK, mBackIntent);
    finish();
}
5. Thư viện: PrinterCommands và Utils dùng để in sau khi kết nối đến máy in thành công

Hai class này giúp ta thiết lập nội dung cần in có thể là chuỗi hoặc hình ảnh, căn chỉnh theo trái phải, kích thước,...vvv





Source code mình có chú thích từng hàm và các phần quan trọng các bạn có thể đọc và tham khảo thêm, có gì chưa hiểu có thể để lại bình luận phía giưới mình sẽ giải đáp
Link tải source code: https://drive.google.com/open?id=1Re718jIdRc9c2Ltz261cthmLKZzv0p9a
Xem thêm: [Phần 2] Kết nối máy in BBPOS SimplyPrint với điện thoại Android qua Bluetooth

1 nhận xét:

Được tạo bởi Blogger.