Blinkid Android SDK可讓您在Android應用中建立出色的入職體驗。
經過一項快速掃描,您的用戶將能夠從其身份證,護照,駕駛執照以及幾乎任何其他政府發行的ID中提取信息。
Blinkid是:
要查看所有這些功能在工作中下載我們的免費演示應用程序:
準備好與集成破解嗎?首先確保我們支持您的文檔類型➡️完整列表。然後遵循以下準則。
UISettings )RecognizerRunnerFragment )RecognizerRunnerViewString識別(解析)BlinkIdUISettings和BlinkIdOverlayControllerDocumentUISettingsLegacyDocumentVerificationUISettingsRecognizerRunner和RecognizerRunnerView處理處理活動Recognizer概念和RecognizerBundleRecognizer概念RecognizerBundleRecognizer物對象libc++_shared.so衝突。Yes 。 RecognizerRunnerFragment並內置相機疊加控制器在您的build.gradle中,將Blinkid Maven存儲庫添加到存儲庫列表
repositories {
maven { url 'https://maven.microblink.com' }
}
將Blinkid添加為依賴性,並確保將transitive設置為true
dependencies {
implementation('com.microblink:blinkid:6.12.0@aar') {
transitive = true
}
}
Android Studio應自動從Maven依賴性導入Javadoc。如果沒有發生,您可以通過遵循以下步驟手動執行此操作:
External Libraries條目(通常這是項目視圖中的最後一個條目)blinkid-6.12.0條目,右鍵單擊並選擇Library Properties...Library Properties彈出窗口將出現+按鈕(包含+的一個小地球)https://blinkid.github.io/blinkid-android/OK 需要有效的許可證密鑰來初始化掃描。您可以在Microblink Developer Hub上註冊後請求免費的試用許可證密鑰。許可證注定要包含您應用程序的包裝名稱,因此請確保在詢問時輸入正確的軟件包名稱。
下載您的許可證文件並將其放入應用程序的資產文件夾中。確保在使用SDK中的任何其他類之前,請確保設置許可證密鑰,否則您將獲得運行時異常。
我們建議您擴展Android應用程序類,並以此方式設置許可證:
public class MyApplication extends Application {
@ Override
public void onCreate () {
MicroblinkSDK . setLicenseFile ( "path/to/license/file/within/assets/dir" , this );
}
} public class MyApplication : Application () {
override fun onCreate () {
MicroblinkSDK .setLicenseFile( " path/to/license/file/within/assets/dir " , this )
}
}在您的主要活動中,通過覆蓋onActivityResult方法來定義和創建ActivityResultLauncher對象。 OneSideDocumentScan和TwoSideDocumentScan都可以互換使用,而實施沒有差異。唯一的功能差異是, OneSideDocumentScan僅掃描文檔的一側,並且TwoSideDocumentScan掃描文檔的一側以上。
ActivityResultLauncher < Void > resultLauncher = registerForActivityResult (
new TwoSideDocumentScan (),
twoSideScanResult -> {
ResultStatus resultScanStatus = twoSideScanResult . getResultStatus ();
if ( resultScanStatus == ResultStatus . FINISHED ) {
// code after a successful scan
// use result.getResult() for fetching results, for example:
String firstName = twoSideScanResult . getResult (). getFirstName (). value ();
} else if ( resultScanStatus == ResultStatus . CANCELLED ) {
// code after a cancelled scan
} else if ( resultScanStatus == ResultStatus . EXCEPTION ) {
// code after a failed scan
}
}
); private val resultLauncher =
registerForActivityResult( TwoSideDocumentScan ()) { twoSideScanResult : TwoSideScanResult ->
when (twoSideScanResult.resultStatus) {
ResultStatus . FINISHED -> {
// code after a successful scan
// use twoSideScanResult.result for fetching results, for example:
val firstName = twoSideScanResult.result?.firstName?.value()
}
ResultStatus . CANCELLED -> {
// code after a cancelled scan
}
ResultStatus . EXCEPTION -> {
// code after a failed scan
}
else -> {}
}
}@Composable
fun createLauncher (): ActivityResultLauncher < Void ?> {
return rememberLauncherForActivityResult( TwoSideDocumentScan ()) { twoSideScanResult : TwoSideScanResult ->
when (twoSideScanResult.resultStatus) {
ResultStatus . FINISHED -> {
// code after a successful scan
// use twoSideScanResult.result for fetching results, for example:
val firstName = twoSideScanResult.result?.firstName?.value()
}
ResultStatus . CANCELLED -> {
// code after a cancelled scan
}
ResultStatus . EXCEPTION -> {
// code after a failed scan
}
else -> {}
}
}
}掃描後,將要更新result ,即OneSideScanResult或TwoSideScanResult對象實例。您可以定義onActivityResult函數覆蓋中數據發生的情況(Kotlin代碼也覆蓋了此函數,但它是隱式的)。在twoSideScanResult.getResult()方法(Kotlin中的twoSideScanResult.result )中可以訪問結果。
通過調用ActivityResultObject並調用ActivityResultLauncher.launch :開始掃描過程:
// method within MyActivity from previous step
public void startScanning () {
// Start scanning
resultLauncher . launch ( null );
} // method within MyActivity from previous step
public fun startScanning () {
// Start scanning
resultLauncher.launch()
} // within @Composable function or setContent block
val resultLauncher = createLauncher()
resultLauncher.launch()結果將在回調中可用,這是在上一步中定義的ActivityResultObject中定義的。
Blinkid需要Android API級別21或更新。
相機視頻預覽分辨率也很重要。為了進行成功的掃描,相機預覽分辨率必須至少為720p。請注意,相機預覽分辨率與視頻記錄分辨率不同。
Blinkid用ARMV7和ARM64本地圖書館二進製文件分發。
Blinkid是一個本地庫,用C ++編寫,可用於多個平台。因此, Blinkid無法在具有晦澀的硬件體系結構的設備上使用。我們僅針對最受歡迎的Android Abis編輯了Blinkid Native代碼。
即使在設置許可證密鑰之前,您也應該檢查當前設備上是否支持BlinkID (請參見下一節:兼容性檢查)。試圖從SDK調用依賴本機代碼的任何方法,例如許可證檢查,在具有不支持的CPU體系結構的設備上會崩潰您的應用程序。
如果將Blinkid庫與其他包含本機代碼的庫相結合到您的應用程序中,請確保與所有本機庫的架構匹配。
有關更多信息,請參見處理器體系結構注意事項部分。
這是您可以檢查設備上是否支持Blinkid的方法:
// check if BlinkID is supported on the device,
RecognizerCompatibilityStatus status = RecognizerCompatibility . getRecognizerCompatibilityStatus ( this );
if ( status == RecognizerCompatibilityStatus . RECOGNIZER_SUPPORTED ) {
Toast . makeText ( this , "BlinkID is supported!" , Toast . LENGTH_LONG ). show ();
} else if ( status == RecognizerCompatibilityStatus . NO_CAMERA ) {
Toast . makeText ( this , "BlinkID is supported only via Direct API!" , Toast . LENGTH_LONG ). show ();
} else if ( status == RecognizerCompatibilityStatus . PROCESSOR_ARCHITECTURE_NOT_SUPPORTED ) {
Toast . makeText ( this , "BlinkID is not supported on current processor architecture!" , Toast . LENGTH_LONG ). show ();
} else {
Toast . makeText ( this , "BlinkID is not supported! Reason: " + status . name (), Toast . LENGTH_LONG ). show ();
} // check if _BlinkID_ is supported on the device,
when ( val status = RecognizerCompatibility .getRecognizerCompatibilityStatus( this )) {
RecognizerCompatibilityStatus . RECOGNIZER_SUPPORTED -> {
Toast .makeText( this , " BlinkID is supported! " , Toast . LENGTH_LONG ).show()
}
RecognizerCompatibilityStatus . NO_CAMERA -> {
Toast .makeText( this , " BlinkID is supported only via Direct API! " , Toast . LENGTH_LONG ).show()
}
RecognizerCompatibilityStatus . PROCESSOR_ARCHITECTURE_NOT_SUPPORTED -> {
Toast .makeText( this , " BlinkID is not supported on current processor architecture! " , Toast . LENGTH_LONG ).show()
}
else -> {
Toast .makeText( this , " BlinkID is not supported! Reason: " + status.name, Toast . LENGTH_LONG ).show()
}
}一些識別器需要帶有自動對焦的相機。如果您嘗試在不支持自動對焦的設備上使用它們,則會出現錯誤。為了防止這種情況,您可以通過調用識別器是否需要自動對焦來檢查其需求方法。
如果您已經有一系列識別器,則可以輕鬆地濾除需要使用以下代碼段從數組中自動對焦的識別器:
Recognizer [] recArray = ...;
if (! RecognizerCompatibility . cameraHasAutofocus ( CameraType . CAMERA_BACKFACE , this )) {
recArray = RecognizerUtils . filterOutRecognizersThatRequireAutofocus ( recArray );
} var recArray : Array < Recognizer > = .. .
if ( ! RecognizerCompatibility .cameraHasAutofocus( CameraType . CAMERA_BACKFACE , this )) {
recArray = RecognizerUtils .filterOutRecognizersThatRequireAutofocus(recArray)
}您可以根據您的用例和自定義需求將Blinkid集成到您的應用中:
OneSideDocumentScan和TwoSideDocumentScan ) - SDK可以處理所有內容,您只需要啟動我們的內置活動並處理結果,沒有自定義選項UISettings ) - SDK處理大部分工作,您只需要定義識別器,設置,啟動我們的內置活動和處理結果,自定義選項有限RecognizerRunnerFragment ) - 在您自己的活動中內置活動中重用掃描UXRecognizerRunnerView ) - SDK在您必須實現完全自定義掃描UX時處理相機管理RecognizerRunner ) - SKD僅處理識別,而您必須從相機或文件提供圖像OneSideDocumentScan和TwoSideDocumentScan ) OneSideDocumentScan和TwoSideDocumentScan是包含所有必要的設置定義的類,以便快速啟動SDK內置掃描活動。它允許用戶跳過所有設置步驟,例如UISettings和RecognizerBundle ,然後直接進行掃描。
如表演所示,您的第一個掃描只需要對結果偵聽器的定義,以定義掃描結果將發生的事情,並調用實際的掃描功能。
UISettings ) UISettings是一個包含SDK內置掃描活動的所有必要設置的課程。它配置掃描活動行為,字符串,圖標和其他UI元素。您應該使用ActivityRunner來啟動由UISettings配置的掃描活動,如下示例所示。
我們提供多個專門用於不同掃描方案的UISettings課程。每個UISettings對像都有屬性,可以通過適當的設置器方法更改。例如,您可以使用setCameraSettings Metod自定義相機設置。
所有可用的UISettings課程都在此處列出。
在您的主要活動中,創建將執行圖像識別的識別器對象,將其配置並將其放入識別器綁定對象。您可以在此處查看有關可用識別器和RecognizerBundle的更多信息。
例如,要掃描支持的文檔,請以這樣的方式配置您的識別器:
public class MyActivity extends Activity {
private BlinkIdMultiSideRecognizer mRecognizer ;
private RecognizerBundle mRecognizerBundle ;
@ Override
protected void onCreate ( Bundle bundle ) {
super . onCreate ( bundle );
// setup views, as you would normally do in onCreate callback
// create BlinkIdMultiSideRecognizer
mRecognizer = new BlinkIdMultiSideRecognizer ();
// bundle recognizers into RecognizerBundle
mRecognizerBundle = new RecognizerBundle ( mRecognizer );
}
} public class MyActivity : Activity () {
private lateinit var mRecognizer : BlinkIdMultiSideRecognizer
private lateinit var mRecognizerBundle : RecognizerBundle
override fun onCreate ( bundle : Bundle ) {
// setup views, as you would normally do in onCreate callback
// create BlinkIdMultiSideRecognizer
mRecognizer = BlinkIdMultiSideRecognizer ()
// build recognizers into RecognizerBundle
mRecognizerBundle = RecognizerBundle (mRecognizer)
}
}通過創建BlinkIdUISettings並調用ActivityRunner.startActivityForResult來開始識別過程:
// method within MyActivity from previous step
public void startScanning () {
// Settings for BlinkIdActivity
BlinkIdUISettings settings = new BlinkIdUISettings ( mRecognizerBundle );
// tweak settings as you wish
// Start activity
ActivityRunner . startActivityForResult ( this , MY_REQUEST_CODE , settings );
} // method within MyActivity from previous step
public fun startScanning () {
// Settings for BlinkIdActivity
val settings = BlinkIdUISettings (mRecognizerBundle)
// tweak settings as you wish
// Start activity
ActivityRunner .startActivityForResult( this , MY_REQUEST_CODE , settings)
}掃描完成後,將在您的活動中調用onActivityResult ,在這裡您可以獲得掃描結果。
@ Override
protected void onActivityResult ( int requestCode , int resultCode , Intent data ) {
super . onActivityResult ( requestCode , resultCode , data );
if ( requestCode == MY_REQUEST_CODE ) {
if ( resultCode == Activity . RESULT_OK && data != null ) {
// load the data into all recognizers bundled within your RecognizerBundle
mRecognizerBundle . loadFromIntent ( data );
// now every recognizer object that was bundled within RecognizerBundle
// has been updated with results obtained during scanning session
// you can get the result by invoking getResult on recognizer
BlinkIdMultiSideRecognizer . Result result = mRecognizer . getResult ();
if ( result . getResultState () == Recognizer . Result . State . Valid ) {
// result is valid, you can use it however you wish
}
}
}
} override protected fun onActivityResult ( requestCode : Int , resultCode : Int , data : Intent ) {
super .onActivityResult(requestCode, resultCode, data);
if (requestCode == MY_REQUEST_CODE ) {
if (resultCode == Activity . RESULT_OK && data != null ) {
// load the data into all recognizers bundled within your RecognizerBundle
mRecognizerBundle.loadFromIntent(data)
// now every recognizer object that was bundled within RecognizerBundle
// has been updated with results obtained during scanning session
// you can get the result by invoking getResult on recognizer
val result = mRecognizer.result
if (result.resultState == Recognizer . Result . State . Valid ) {
// result is valid, you can use it however you wish
}
}
}
}有關可用識別器和RecognizerBundle的更多信息,請參見識別器串和可用的識別器。
RecognizerRunnerFragment )如果您想在自己的活動中重複使用我們內置的活動UX,請使用RecognizerRunnerFragment 。將託管RecognizerRunnerFragment的活動必須實現ScanningOverlayBinder接口。試圖將RecognizerRunnerFragment添加到無法實現該接口的活動中會導致ClassCastException 。
ScanningOverlayBinder負責返回ScanningOverlay的non-null實現 - 將在RecognizerRunnerFragment上管理UI的類。不建議創建自己的ScanningOverlay實現,而是使用此處列出的一個實現之一。
這是主持RecognizerRunnerFragment的活動的最低示例:
public class MyActivity extends AppCompatActivity implements RecognizerRunnerFragment . ScanningOverlayBinder {
private BlinkIdMultiSideRecognizer mRecognizer ;
private RecognizerBundle mRecognizerBundle ;
private BlinkIdOverlayController mScanOverlay ;
private RecognizerRunnerFragment mRecognizerRunnerFragment ;
@ Override
protected void onCreate ( Bundle savedInstanceState ) {
super . onCreate ();
setContentView ( R . layout . activity_my_activity );
mScanOverlay = createOverlay ();
if ( null == savedInstanceState ) {
// create fragment transaction to replace R.id.recognizer_runner_view_container with RecognizerRunnerFragment
mRecognizerRunnerFragment = new RecognizerRunnerFragment ();
FragmentTransaction fragmentTransaction = getSupportFragmentManager (). beginTransaction ();
fragmentTransaction . replace ( R . id . recognizer_runner_view_container , mRecognizerRunnerFragment );
fragmentTransaction . commit ();
} else {
// obtain reference to fragment restored by Android within super.onCreate() call
mRecognizerRunnerFragment = ( RecognizerRunnerFragment ) getSupportFragmentManager (). findFragmentById ( R . id . recognizer_runner_view_container );
}
}
@ Override
@ NonNull
public ScanningOverlay getScanningOverlay () {
return mScanOverlay ;
}
private BlinkIdOverlayController createOverlay () {
// create BlinkIdMultiSideRecognizer
mRecognizer = new BlinkIdMultiSideRecognizer ();
// bundle recognizers into RecognizerBundle
mRecognizerBundle = new RecognizerBundle ( mRecognizer );
BlinkIdUISettings settings = new BlinkIdUISettings ( mRecognizerBundle );
return settings . createOverlayController ( this , mScanResultListener );
}
private final ScanResultListener mScanResultListener = new ScanResultListener () {
@ Override
public void onScanningDone ( @ NonNull RecognitionSuccessType recognitionSuccessType ) {
// pause scanning to prevent new results while fragment is being removed
mRecognizerRunnerFragment . getRecognizerRunnerView (). pauseScanning ();
// now you can remove the RecognizerRunnerFragment with new fragment transaction
// and use result within mRecognizer safely without the need for making a copy of it
// if not paused, as soon as this method ends, RecognizerRunnerFragments continues
// scanning. Note that this can happen even if you created fragment transaction for
// removal of RecognizerRunnerFragment - in the time between end of this method
// and beginning of execution of the transaction. So to ensure result within mRecognizer
// does not get mutated, ensure calling pauseScanning() as shown above.
}
@ Override
public void onUnrecoverableError ( @ NonNull Throwable throwable ) {
}
};
} package com.microblink.blinkid
class MainActivity : AppCompatActivity (), RecognizerRunnerFragment.ScanningOverlayBinder {
private lateinit var mRecognizer : BlinkIdMultiSideRecognizer
private lateinit var mRecognizerRunnerFragment : RecognizerRunnerFragment
private lateinit var mRecognizerBundle : RecognizerBundle
private lateinit var mScanOverlay : BlinkIdOverlayController
override fun onCreate ( savedInstanceState : Bundle ? ) {
super .onCreate(savedInstanceState)
if ( ! ::mScanOverlay.isInitialized) {
mScanOverlay = createOverlayController()
}
setContent {
this . run {
// viewBinding has to be set to 'true' in buildFeatures block of the build.gradle file
AndroidViewBinding ( RecognizerRunnerLayoutBinding ::inflate) {
mRecognizerRunnerFragment =
fragmentContainerView.getFragment< RecognizerRunnerFragment >()
}
}
}
}
override fun getScanningOverlay (): ScanningOverlay {
return mScanOverlay
}
private fun createOverlay (): BlinkIdOverlayController {
// create BlinkIdMultiSideRecognizer
val mRecognizer = BlinkIdMultiSideRecognizer ()
// bundle recognizers into RecognizerBundle
mRecognizerBundle = RecognizerBundle (mRecognizer)
val settings = BlinkIdUISettings (mRecognizerBundle)
return settings.createOverlayController( this , mScanResultListener)
}
private val mScanResultListener : ScanResultListener = object : ScanResultListener {
override fun onScanningDone ( p0 : RecognitionSuccessType ) {
// pause scanning to prevent new results while fragment is being removed
mRecognizerRunnerFragment !! .recognizerRunnerView !! .pauseScanning()
// now you can remove the RecognizerRunnerFragment with new fragment transaction
// and use result within mRecognizer safely without the need for making a copy of it
// if not paused, as soon as this method ends, RecognizerRunnerFragments continues
// scanning. Note that this can happen even if you created fragment transaction for
// removal of RecognizerRunnerFragment - in the time between end of this method
// and beginning of execution of the transaction. So to ensure result within mRecognizer
// does not get mutated, ensure calling pauseScanning() as shown above.
}
override fun onUnrecoverableError ( p0 : Throwable ) {
}
}
}請參閱SDK提供的示例應用程序,以獲取更詳細的示例,並確保主機活動的方向設置為nosensor或已啟用了配置更改(IE在配置更改時未重新啟動)。有關更多信息,請檢查掃描方向部分。
RecognizerRunnerView本節討論瞭如何將識別性的Ernizerrunnerview嵌入到您的掃描活動中並進行掃描。
RecognizerRunnerView是您活動中的成員字段。這是必需的,因為您需要將所有活動的生命週期事件傳遞給RecognizerRunnerView 。portrait或landscape 。設置sensor作為掃描活動的方向,每當設備方向變化時,都會觸發全面的活動。這將提供非常糟糕的用戶體驗,因為相機和Blinkid Native Library每次都必須重新啟動。有針對這種行為的措施將在後面討論。onCreate方法中,創建一個新的RecognizerRunnerView ,設置識別器包含識別器,該識別器將通過視圖使用,定義將處理強制性攝像機事件的cameraeventsListener,定義ScanResultListener,定義scanResultListener,該scanResultListener將在識別完成時接收呼叫,然後呼叫其create方法。之後,添加應該在相機視圖頂部佈局的視圖。setLifecycle方法傳遞活動的生命週期,以自動處理生命週期事件。以下是將RecognizerRunnerView性的最低示例作為您活動中唯一的觀點:
public class MyScanActivity extends AppCompatActivity {
private static final int PERMISSION_CAMERA_REQUEST_CODE = 42 ;
private RecognizerRunnerView mRecognizerRunnerView ;
private BlinkIdMultiSideRecognizer mRecognizer ;
private RecognizerBundle mRecognizerBundle ;
@ Override
protected void onCreate ( Bundle savedInstanceState ) {
super . onCreate ( savedInstanceState );
// create BlinkIdMultiSideRecognizer
mRecognizer = new BlinkIdMultiSideRecognizer ();
// bundle recognizers into RecognizerBundle
mRecognizerBundle = new RecognizerBundle ( mRecognizer );
// create RecognizerRunnerView
mRecognizerRunnerView = new RecognizerRunnerView ( this );
// set lifecycle to automatically call recognizer runner view lifecycle methods
mRecognizerRunnerView . setLifecycle ( getLifecycle ());
// associate RecognizerBundle with RecognizerRunnerView
mRecognizerRunnerView . setRecognizerBundle ( mRecognizerBundle );
// scan result listener will be notified when scanning is complete
mRecognizerRunnerView . setScanResultListener ( mScanResultListener );
// camera events listener will be notified about camera lifecycle and errors
mRecognizerRunnerView . setCameraEventsListener ( mCameraEventsListener );
setContentView ( mRecognizerRunnerView );
}
@ Override
public void onConfigurationChanged ( Configuration newConfig ) {
super . onConfigurationChanged ( newConfig );
// changeConfiguration is not handled by lifecycle events so call it manually
mRecognizerRunnerView . changeConfiguration ( newConfig );
}
private final CameraEventsListener mCameraEventsListener = new CameraEventsListener () {
@ Override
public void onCameraPreviewStarted () {
// this method is from CameraEventsListener and will be called when camera preview starts
}
@ Override
public void onCameraPreviewStopped () {
// this method is from CameraEventsListener and will be called when camera preview stops
}
@ Override
public void onError ( Throwable exc ) {
/**
* This method is from CameraEventsListener and will be called when
* opening of camera resulted in exception or recognition process
* encountered an error. The error details will be given in exc
* parameter.
*/
}
@ Override
@ TargetApi ( 23 )
public void onCameraPermissionDenied () {
/**
* Called in Android 6.0 and newer if camera permission is not given
* by user. You should request permission from user to access camera.
*/
requestPermissions ( new String []{ Manifest . permission . CAMERA }, PERMISSION_CAMERA_REQUEST_CODE );
/**
* Please note that user might have not given permission to use
* camera. In that case, you have to explain to user that without
* camera permissions scanning will not work.
* For more information about requesting permissions at runtime, check
* this article:
* https://developer.android.com/training/permissions/requesting.html
*/
}
@ Override
public void onAutofocusFailed () {
/**
* This method is from CameraEventsListener will be called when camera focusing has failed.
* Camera manager usually tries different focusing strategies and this method is called when all
* those strategies fail to indicate that either object on which camera is being focused is too
* close or ambient light conditions are poor.
*/
}
@ Override
public void onAutofocusStarted ( Rect [] areas ) {
/**
* This method is from CameraEventsListener and will be called when camera focusing has started.
* You can utilize this method to draw focusing animation on UI.
* Areas parameter is array of rectangles where focus is being measured.
* It can be null on devices that do not support fine-grained camera control.
*/
}
@ Override
public void onAutofocusStopped ( Rect [] areas ) {
/**
* This method is from CameraEventsListener and will be called when camera focusing has stopped.
* You can utilize this method to remove focusing animation on UI.
* Areas parameter is array of rectangles where focus is being measured.
* It can be null on devices that do not support fine-grained camera control.
*/
}
};
private final ScanResultListener mScanResultListener = new ScanResultListener () {
@ Override
public void onScanningDone ( @ NonNull RecognitionSuccessType recognitionSuccessType ) {
// this method is from ScanResultListener and will be called when scanning completes
// you can obtain scanning result by calling getResult on each
// recognizer that you bundled into RecognizerBundle.
// for example:
BlinkIdMultiSideRecognizer . Result result = mRecognizer . getResult ();
if ( result . getResultState () == Recognizer . Result . State . Valid ) {
// result is valid, you can use it however you wish
}
// Note that mRecognizer is stateful object and that as soon as
// scanning either resumes or its state is reset
// the result object within mRecognizer will be changed. If you
// need to create a immutable copy of the result, you can do that
// by calling clone() on it, for example:
BlinkIdMultiSideRecognizer . Result immutableCopy = result . clone ();
// After this method ends, scanning will be resumed and recognition
// state will be retained. If you want to prevent that, then
// you should call:
mRecognizerRunnerView . resetRecognitionState ();
// Note that reseting recognition state will clear internal result
// objects of all recognizers that are bundled in RecognizerBundle
// associated with RecognizerRunnerView.
// If you want to pause scanning to prevent receiving recognition
// results or mutating result, you should call:
mRecognizerRunnerView . pauseScanning ();
// if scanning is paused at the end of this method, it is guaranteed
// that result within mRecognizer will not be mutated, therefore you
// can avoid creating a copy as described above
// After scanning is paused, you will have to resume it with:
mRecognizerRunnerView . resumeScanning ( true );
// boolean in resumeScanning method indicates whether recognition
// state should be automatically reset when resuming scanning - this
// includes clearing result of mRecognizer
}
};
}如果AndroidManifest.xml中的Activity的screenOrientation屬性設置為sensor , fullSensor或類似的活動,則每當設備從肖像變為景觀,反之亦然,將重新啟動活動。在重新啟動活動時,將調用其onPause , onStop和onDestroy方法,然後將重新創建新的活動。這是掃描活動的潛在問題,因為在其生命週期中,它控制著相機和本地庫 - 重新啟動該活動將觸發相機和本地庫的重新啟動。這是一個問題,因為從景觀到肖像的方向變化,反之亦然,將非常慢,從而降低了用戶體驗。我們不建議這樣的設置。
為此,我們建議將您的掃描活動設置為portrait或landscape模式,並手動處理設備方向更改。為了幫助您,無論活動的screenOrientation如何, RecognizerRunnerView支持將添加將旋轉的子觀點添加。您將希望旋轉的視圖(例如包含按鈕,狀態消息等視圖)使用AddChildView方法RecognizerRunnerView 。該方法的第二個參數是一個布爾值,該參數定義了您要添加的視圖是否將使用設備旋轉。為了定義允許的方向,請實現OrientationAllowEdlistener接口,並使用Method setOrientationAllowedListener將其添加到RecognizerRunnerView中。這是旋轉攝像頭覆蓋的推薦方法。
但是,如果您真的想將screenOrientation屬性設置為sensor或類似的篩選屬性,並且希望Android處理掃描活動的方向更改,那麼我們建議將活動的configChanges屬性設置為orientation|screenSize 。這將使Android在設備方向更改時不要重新啟動您的活動。取而代之的是,將調用Activity的onConfigurationChanged方法,以便可以通知活動的配置更改。在實現此方法時,您應該調用RecognizerView的changeConfiguration方法,以便它可以使其相機表面和兒童視圖適應新配置。
本節將描述如何使用直接API識別Android位圖而無需相機。您可以在應用程序中的任何地方使用直接API,而不僅僅是通過活動。
圖像識別性能在很大程度上取決於輸入圖像的質量。當使用相機管理(從相機掃描)時,我們會盡力獲取具有最佳質量的相機框架。另一方面,當使用直接API時,您需要提供高質量的圖像,而無需模糊和眩光以成功識別。
Bitmaps 。使用識別bitbitmap或識別bitmapwithRevithizer。Images 。識別將針對速度進行優化,並將依靠連續的視頻幀之間的時間差,以產生最佳的識別結果。使用識別videoimage或識別vIDEOIMAGEWITHRECOGNIZER。Images仍需要從單個InputImage中獲得最佳結果。 inputImage類型來自我們的SDK,也可以使用ImageBuilder創建它。使用識別量或識別詞。這是用於識別Android位圖的直接API使用的最小示例:
public class DirectAPIActivity extends Activity {
private RecognizerRunner mRecognizerRunner ;
private BlinkIdMultiSideRecognizer mRecognizer ;
private RecognizerBundle mRecognizerBundle ;
@ Override
protected void onCreate ( Bundle savedInstanceState ) {
super . onCreate ();
// initialize your activity here
// create BlinkIdMultiSideRecognizer
mRecognizer = new BlinkIdMultiSideRecognizer ();
// bundle recognizers into RecognizerBundle
mRecognizerBundle = new RecognizerBundle ( mRecognizer );
try {
mRecognizerRunner = RecognizerRunner . getSingletonInstance ();
} catch ( FeatureNotSupportedException e ) {
Toast . makeText ( this , "Feature not supported! Reason: " + e . getReason (). getDescription (), Toast . LENGTH_LONG ). show ();
finish ();
return ;
}
mRecognizerRunner . initialize ( this , mRecognizerBundle , new DirectApiErrorListener () {
@ Override
public void onRecognizerError ( Throwable t ) {
Toast . makeText ( DirectAPIActivity . this , "There was an error in initialization of Recognizer: " + t . getMessage (), Toast . LENGTH_SHORT ). show ();
finish ();
}
});
}
@ Override
protected void onResume () {
super . onResume ();
// start recognition
Bitmap bitmap = BitmapFactory . decodeFile ( "/path/to/some/file.jpg" );
mRecognizerRunner . recognizeBitmap ( bitmap , Orientation . ORIENTATION_LANDSCAPE_RIGHT , mScanResultListener );
}
@ Override
protected void onDestroy () {
super . onDestroy ();
mRecognizerRunner . terminate ();
}
private final ScanResultListener mScanResultListener = new ScanResultListener () {
@ Override
public void onScanningDone ( @ NonNull RecognitionSuccessType recognitionSuccessType ) {
// this method is from ScanResultListener and will be called
// when scanning completes
// you can obtain scanning result by calling getResult on each
// recognizer that you bundled into RecognizerBundle.
// for example:
BlinkIdMultiSideRecognizer . Result result = mRecognizer . getResult ();
if ( result . getResultState () == Recognizer . Result . State . Valid ) {
// result is valid, you can use it however you wish
}
}
};
} scanResultListener.scanningdone方法被調用您發送到識別的每個輸入映像。您可以使用同一文檔的不同圖像來調用RecognizerRunner.recognize*方法,以提高閱讀精度,直到您在聽眾的onScanningDone方法中獲得成功的結果。當您使用自己的或第三方攝像頭管理時,這很有用。
String識別(解析)一些識別者支持String識別。它們可以通過直接API使用來解析給定String並返回數據,就像在輸入圖像上使用時一樣。當在String上執行識別時,無需OCR。輸入String使用方式與識別圖像時使用的OCR輸出相同。
String的識別可以與上一節中描述的圖像識別相同的方式執行。
唯一的區別是,應稱為識別字符串識別方法之一:
Direct API的RecognizerRunner Singleton是一台可以在3個州之一中的州機器: OFFLINE , READY和WORKING 。
RecognizerRunner singleton的引用時,它將處於OFFLINE狀態。RecognizerRunner 。如果您在RecognizerRunner處於OFFLINE狀態時調用initialize方法,則將獲得IllegalStateException 。RecognizerRunner將移至READY狀態。現在,您可以調用任何recognize*方法。recognize*方法開始識別時, RecognizerRunner將轉移到WORKING狀態。如果您嘗試在RecognizerRunner不READY狀態時調用這些方法,您將獲得IllegalStateExceptionRecognizerRunner's方法RecognizerRunner首先移回READY狀態,然後調用提供的ScanResultListener的scanningdone方法。ScanResultListener的onScanningDone方法,因此請確保您在此回調中不執行UI操作。還要注意,即使在過渡到READY狀態後, RecognizerRunner在onScanningDone方法完成之前,即使在剛剛調用了任何recognize*方法。這是為了確保與RecognizerRunner RecognizerBundle捆綁在一起的識別器的結果未經修改,而可能在onScanningDone方法中使用。terminate方法, RecognizerRunner singleton將發布其所有內部資源。請注意,即使呼叫terminate後,您可能會在terminate時onScanningDone工作。RecognizerRunner singleton的狀態調用terminate方法getCurrentState觀察RecognizerRunner singleton的狀態nessizerrunnerview和RecognizerRunner都使用與管理本機代碼相同的內部單例。這個單身人士處理本地庫的初始化和終止,並將識別器傳播到本地庫。可以將RecognizerRunnerView和RecognizerRunner一起使用,因為內部單例將確保使用正確的同步和正確的識別設置。如果您在使用RecognizerRunner與RecognizerRunnerView結合使用時遇到問題,請告訴我們!
當您使用合併的識別器和兩個文檔側面的圖像時,您需要多次調用RecognizerRunner.recognize* 。首先將其稱為文檔的第一側的圖像,直到讀取為止,然後使用第二側的圖像。合併的識別器成功讀取第一側後,自動切換到第二側掃描。要在完成第一側掃描完成時被通知,您必須通過MetadataCallbacks設置FirstSiderEcognitionCallback。如果您不需要這些信息,例如,當每個文檔端只有一個圖像時,請不要設置FirstSideRecognitionCallback ,並在處理第二個側面圖像之後,在scanResultListener中檢查識別succescessType。
BlinkIdUISettings和BlinkIdOverlayController BlinkIdOverlayController實現了用於掃描身份文檔的新UI,最佳設計可與新的BlinkIdMultiSideRecognizer和BlinkIdSingleSideRecognizer一起使用。它實現了幾個新功能:
新的UI允許用戶以任何方向掃描文檔。如果您在背面掃描條形碼,我們建議強制景觀取向,因為在該方向上的成功率將更高。
啟動使用BlinkIdOverlayController的內置活動,請使用BlinkIdUISettings 。
要自定義覆蓋層,請通過BlinkIdUISettings.setOverlayViewStyle()方法或ReticleOverlayView構造器提供您的自定義樣式資源。您可以通過在您的樣式中提供以下屬性來自定義上面屏幕截圖上標記的元素:
出口
mb_exitScanDrawable可繪製圖標BlinkIdUISettings.setShowCancelButton(false)禁用此元素火炬
mb_torchOnDrawable啟用火炬時顯示的圖標可繪製mb_torchOffDrawable禁用火炬時顯示的圖標可繪製BlinkIdUISettings.setShowTorchButton(false)禁用此元素指示
mb_instructionsTextAppearance將用作android:textAppearancemb_instructionsBackgroundDrawable -drawable -drawable用於背景mb_instructionsBackgroundColor用於背景的顏色手電筒警告
mb_flashlightWarningTextAppearance將用作android:textAppearancemb_flashlightWarningBackgroundDrawable -drawable -drawable用於背景BlinkIdUISettings.setShowFlashlightWarning(false)禁用此元素卡圖標
mb_cardFrontDrawable卡片翻轉動畫中顯示的圖標可繪製,代表卡的前側mb_cardBackDrawable卡片翻轉動畫中顯示的圖標可繪製,代表卡的背面標線
mb_reticleDefaultDrawable標線處於中性狀態時顯示可繪製mb_reticleSuccessDrawable可繪製的標線處於成功狀態時(掃描成功)mb_reticleErrorDrawable標線處於錯誤狀態時顯示的可繪製mb_reticleColor用於旋轉標線元件的顏色mb_reticleDefaultColor用於中性狀態的標線顏色mb_reticleErrorColor用於標線處於錯誤狀態的顏色mb_successFlashColor用於閃光效果的顏色成功掃描為了自定義這兩個對話框的可見性和样式,請使用BlinkIdUISettings中提供的方法。
控制簡介對話框可見性的方法是BlinkIdUISettings.setShowIntroductionDialog(boolean showIntroductionDialog) ,默認情況下將其設置為true,這意味著將顯示“簡介”對話框。
控制入門對話框可見性的方法是BlinkIdUISettings.setShowOnboardingInfo(boolean showOnboardingInfo) ,默認情況下將其設置為true,這意味著將顯示“簡介”對話框。
還有一種控制“顯示幫助”的延遲的方法。在幫助按鈕上方顯示的工具提示。如果先前顯示入板的方法為真,則將顯示按鈕本身。設置工具提示延遲長度的方法是BlinkIdUISettings.setShowTooltipTimeIntervalMs(long showTooltipTimeIntervalMs) 。時間參數以毫秒為單位。
延遲的默認設置為12秒(12000毫秒)。
通過提供以下屬性,可以以與上一章中解釋的方式進行自定義和主題來進行這些介紹和入職元素:
幫助按鈕
mb_helpButtonDrawable啟用幫助按鈕時顯示的可繪製mb_helpButtonBackgroundColor用於幫助按鈕背景的顏色mb_helpButtonQuestionmarkColor用於幫助按鈕的顏色前景幫助工具提示
mb_helpTooltipBackground可繪製的繪製,當幫助工具提示彈出時,該背景顯示為背景mb_helpTooltipColor用於幫助工具提示背景的顏色mb_helpTooltipTextAppearance將用作android:textAppearance簡介對話框
mb_introductionBackgroundColor用於簡介屏幕背景的顏色mb_introductionTitleTextAppearance將用作android:textAppearancemb_introductionMessageTextAppearance將用作android:textAppearancemb_introductionButtonTextAppearance將用作android:textAppearanceBlinkIdUISettings.setShowIntroductionDialog(false)禁用此元素入職對話框
mb_onboardingBackgroundColor用於入型屏幕背景的顏色mb_onboardingPageIndicatorColor用於登機屏幕中的圓形頁面指示器的顏色mb_onboardingTitleTextAppearance將用作android:textAppearancemb_onboardingMessageTextAppearance將用作android:textAppearancemb_onboardingButtonTextAppearance將用作android:textAppearanceBlinkIdUISettings.setShowOnboardingInfo(false)禁用此元素SDK調用的警報對話框具有自己的一組屬性,可以在styles.xml中修改。
MB_alert_dialog是一個擴展Theme.AppCompat.Light.Dialog.Alert主題的主題,並使用應用程序主題的默認顏色。為了更改這些警報對話框中的屬性,而無需更改用戶應用程序中的其他屬性, MB_alert_dialog主題需要覆蓋。
< style name = " MB_alert_dialog " parent = " Theme.AppCompat.Light.Dialog.Alert " >
< item name = " android:textSize " >TEXT_SIZE</ item >
< item name = " android:background " >COLOR</ item >
< item name = " android:textColorPrimary " >COLOR</ item >
< item name = " colorAccent " >COLOR</ item >
</ style >未覆蓋的屬性將使用應用程序主題的默認顏色和大小。
colorAccent Attibute用於更改“警報”對話框按鈕的顏色。如果更改了應用程序主題的colorAccent屬性,則此警報對話框按鈕顏色也將更改。但是,覆蓋MB_alert_dialog主題及其其中的此屬性將確保更改Microblink SDK中的按鈕顏色。如果應用程序主題擴展了一個主題,請參見MaterialComponents集合集(例如Theme.MaterialComponents.Light.NoActionBar ),則只能通過覆蓋colorOnPrimary屬性而不是colorAccent屬性來更改上述按鈕顏色。
DocumentUISettings DocumentUISettings啟動了使用BlinkIdOverlayController和替代UI的活動。它最適合掃描各種卡文檔的單個文檔側,不應與組合識別器一起使用,因為它沒有提供有關何時切換到背面的用戶說明。
LegacyDocumentVerificationUISettings LegacyDocumentVerificationUISettings啟動了使用替代UI的BlinkIdOverlayController的活動。它最適合組合識別器,因為它可以管理單個攝像頭打開的多個文檔側面的掃描,並指導用戶完成掃描過程。它也可用於單側掃描身份證,護照,駕駛執照等。
內置活動和覆蓋物中使用的字符串可以定位於任何語言。如果您在自定義掃描活動或片段中使用RecognizerRunnerView (有關更多信息,請參見本章),則應像其他任何Android應用程序一樣處理本地化。 RecognizerRunnerView不使用字符串或可繪製物,它僅使用assets/microblink文件夾中的資產。這些資產不得觸摸,因為識別正確工作所需的必要條件。
但是,如果您使用我們的內置活動或覆蓋層,它們將使用LibBlinkID.aar中包裝的資源。AAR在相機視圖頂部顯示字符串和圖像。我們已經準備了幾種語言的字符串,您可以開箱即用。您也可以修改這些字符串,也可以添加自己的語言。
要使用一種語言,您必須從代碼中啟用它:
要使用某種語言,在應用程序啟動時,在打開SDK的任何UI組件之前,您應該調用Method LanguageUtils.setLanguageAndCountry(language, country, context) 。例如,您可以這樣將語言設置為克羅地亞語:
// define BlinkID language
LanguageUtils . setLanguageAndCountry ( "hr" , "" , this );Blinkid可以輕鬆地翻譯成其他語言。 LibBlinkID.aar中的res文件夾。AAR存檔中的文件夾values ,其中包含strings.xml此文件包含英語字符串。為了進行Croatian翻譯,請在您的項目中創建一個文件夾values-hr ,然後將strings.xml的副本放入其中(您可能需要提取LibBlinkID.aar檔案以訪問這些文件)。然後,打開該文件,將字符串從英語轉換為克羅地亞人。
要修改現有字符串,最好的方法是:
LibBlinkID.aar的文件夾res/values-hr中查找strings.xml存檔<string name="MBBack">Back</string>res/values-hr中創建一個file strings.xml ,如果尚不存在<string name="MBBack">Natrag</string>RecognizerRunner和RecognizerRunnerView處理處理活動處理事件(也稱為元數據回調)純粹旨在使用Blinkid SDK在應用程序開發時捕獲對UI的處理反饋或捕獲一些調試信息。因此,內置的活動和碎片在內部處理這些事件。如果您需要自己處理這些事件,則需要使用venteizerrunnerview或venterizerrunner。
所有事件的回調都捆綁到MetadataCallbacks對像中。 ensunizerrunner和nectizerrunnerview都有可以讓您設置所有回調的方法。
我們建議您查看有關可用回調和事件的更多信息,您可以在Javadoc中處理getadataCallbacks類。
請注意,這兩種方法都需要將有關可用回調的信息傳遞到本機代碼,並且出於效率原因,這是在調用setMetadataCallbacks方法的情況下完成的,而不是每次發生變化在MetadataCallbacks對像中。這意味著,例如,如果您已經稱為setMetadataCallbacks方法,則將QuadDetectionCallback設置為MetadataCallbacks ,則QuadDetectionCallback將不會在本機代碼中註冊,並且您將不會收到其事件。
同樣,例如,如果您已經調用了setMetadataCallbacks方法,則從MetadataCallbacks對像中刪除QuadDetectionCallback ,當我們的處理代碼嘗試在刪除呼叫(現在設置為null )上時,您的應用程序將使用NullPointerException崩潰。由於兩個原因,我們故意在此處進行null檢查:
null回調,在仍在本機代碼中註冊的同時是您程序的非法狀態,因此應該崩潰請記住,每次您對MetadataCallbacks對象進行一些更改時,都需要通過調用其setMetadataCallbacks方法將這些更改應用於RecognizerRunner或RecognizerRunnerView 。
Recognizer概念和RecognizerBundle本節將首先描述什麼是Recognizer ,以及如何使用它來執行圖像,視頻和相機流的識別。接下來,我們將描述如何使用RecognizerBundle來調整識別過程並在活動之間傳輸Recognizer物對象。
識別器串是一個包裹識別器並定義有關應如何執行識別的對象。除此之外, RecognizerBundle使可以在不同活動之間傳輸Recognizer物對象,這是在使用內置活動執行掃描時所必需的,如第一個掃描部分所述,但是當您需要在活動之間傳遞Recognizer對象時,也很方便。
可以在此處找到所有可用Recognizer對象的列表,並簡要介紹了每個Recognizer ,其目的和建議應如何用於獲得最佳性能和用戶體驗。
Recognizer概念識別器是Blinkid SDK中處理的基本單位。其主要目的是處理圖像並從中提取有意義的信息。如您稍後會看到的那樣, Blinkid SDK具有許多具有不同目的的不同Recognizer物對象。
每個Recognizer都有一個Result對象,其中包含從圖像中提取的數據。 Result對像是相應Recognizer對象的成員,其壽命與其父Recognizer對象的壽命綁定。如果您需要Result對像以超過其父Recognizer對象,則必須通過調用其方法clone()來製作其副本。
每個Recognizer都是一個狀態對象,可以在兩個狀態:閒置狀態和工作狀態。在閒置狀態時,您可以通過其Getter和setter調整Recognizer對象的屬性。將其捆綁到RecognizerBundle串中並使用ensenizerrunner或nekenizerrunnerview將處理處理與所有Recognizer對象捆綁在一起的所有RecognizerBundle器對象,它將更改為工作狀態,以便在Recognizer對像用於處理的位置。在工作狀態時,您無法調整Recognizer器對象的屬性。如果需要,則必須通過調用其clone()來創建Recognizer對象的副本,然後調整該副本,將其捆綁到新的RecognizerBundle中,然後使用reconfigureRecognizers ,以確保將新的捆綁包用於處理線程中。
儘管Recognizer物對像有效,但它會改變其內部狀態及其結果。 Recognizer對象的Result總是以空狀態開始。當相應的Recognizer對像對給定圖像進行識別時,其Result可以保持Empty狀態(以防Recognizer無法執行識別),移至不確定狀態(如果Recognizer Recognizer Recognizer ,但並非所有強制性信息都被提取) 。
一旦一個Recognizer物對像在RecognizerBundle中的Result或RecognizerRunnerView更改對Valid狀態的更改,則將在執行背景處理的同一線程上調用onScanningDone回調,並且您將有機會檢查每個Recognizer器對象的Results RecognizerRunner以查看哪個結果已移至Valid狀態。
正如有關RecognizerRunnerView的部分已經指出的那樣,一旦在onScanningDone方法結束時, RecognizerRunnerView將繼續處理具有相同Recognizer對象的新相機框架,除非暫停。繼續處理或重置識別將修改或重置所有Recognizer器對象的Results 。當使用內置活動時,一旦調用了onScanningDone ,內置的活動就會暫停RecognizerRunnerView並開始完成該活動,同時將具有主動Recognizer器對象的RecognizerBundle扣為Intent ,以便將它們轉移回呼叫活動。
RecognizerBundle識別器圍繞是圍繞識別物對象包裝的,可用於在活動之間傳輸Recognizer對象,並將Recognizer對象與RecognizerRunner或RecognizerRunnerView進行處理。
RecognizerBundle圍繞始終由需要準備識別Recognizer器對象構建(即必須對其屬性進行調整)。 varargs構造函數使得無需創建臨時數組就可以更輕鬆地將Recognizer像傳遞到它。
RecognizerBundle圍繞在識別過程中管理Recognizer器對象鏈。當新圖像到達時,它是由鏈中的第一個Recognizer處理的,然後在第二個且依此類推,迭代,直到Recognizer對象的Result將其狀態更改為Valid或鏈中的所有Recognizer對像都被調用(沒有任何Valid結果狀態)。如果您想調用鏈中的所有Recognizers ,無論某些Recognizer對象的鏈中是否將其Result更改為Valid ,則可以允許在單個圖像上返回多個結果。
您無法更改鏈中Recognizer對象的順序 - 無論您給Recognizer RecognizerBundle對象識別對象的順序如何,它們都是內部訂購的,以提供最佳的性能和準確性。同樣,為了使Blinkid SDK能夠以最佳方式訂購識別鏈中的Recognizer器對象,因此不允許在鏈中具有相同類型的多個Recognizer物對象。嘗試這樣做會崩潰您的應用程序。
Recognizer物對象除了管理Recognizer器對象的鏈外, RecognizerBundle還管理應用程序中不同活動之間的捆綁Recognizer物對象。儘管每個Recognizer對象及其Result對像都實現了可穿戴的接口,但將這些對象置於意圖並在您的活動和服務之間傳遞並不是很簡單,原因有兩個:
Result對象與其Recognizer對象綁定,該對像管理本機Result對象的壽命。Result對象通常包含大型數據塊,例如圖像,由於Android的意圖交易數據限制,無法通過Intent傳輸。儘管第一個問題可以通過製作Result的副本並獨立轉移來輕鬆解決,但第二個問題很難應對。在這裡, RecognizerBundle's方法savetent和loadFromintent可以提供幫助,因為它們確保了Recognizer對象的安全傳遞,該識別器的對像根據使用方法setIntentDataTransferMode在活動之間捆綁在RecognizerBundle中的識別器捆綁中,
STANDARD ,則使用正常意圖交易機制通過Intent傳遞Recognizer器對象,該機制受Android的意圖交易數據限制的限制。這與手動將Recognizer對象的Intent相同,只要您不使用在其Results中產生圖像或其他大對象的Recognizer對象。OPTIMISED , Recognizer對象將通過內部Singleton對像傳遞,並且不會進行任何序列化。這意味著要傳遞的數據大小沒有限制。這也是最快的傳輸方法,但是它具有嚴重的缺點 - 如果Android殺死您的應用程序以節省其他應用程序的內存,然後稍後重新啟動它,並重新啟動應包含Recognizer器對象的重新Intent ,則應包含保存的Recognizer對象的內部單例將是空的,並且發送的數據將被丟失。您可以通過在設備的開發人員選項中選擇不選擇背景過程的背景過程,然後從您的應用程序切換到另一個應用程序,然後返回您的應用程序,從而輕鬆啟動該條件。PERSISTED_OPTIMISED ,則Recognizer對象將通過Internal Singleton對象(就像在OPTIMISED模式下一樣)傳遞,並將額外序列化到您應用程序的私有文件夾中的文件中。如果Android重新啟動您的應用程序,並且內部Singleton在重新交付Intent後是空的,則將從文件加載數據,並且不會丟失。當數據讀數發生時,將自動清理文件。就像OPTIMISED一樣,此模式沒有限制正在傳遞的數據大小,並且沒有OPTIMISED模式的缺點,但是有些用戶可能會擔心編寫數據的文件。saveState方法來實現onSaveInstanceState並將捆綁包回到文件中。另外,在保存狀態之後,您應該確保在不onResume onCreate保存的狀態,因為如果活動不重新啟動,則可能不會在onSaveInstanceState啟動,即使您的活動進入後台(在onStop之前),即使活動可能不會在以後殺死活動。OPTIMISED模式在活動之間傳輸大數據和圖像或創建自己的數據傳輸機制。請注意,除非將最終用戶的設備植根,否則您的應用程序和應用程序只能訪問您的應用程序的私有文件夾。本節將提供Blinkid SDK中可用的所有Recognizer物對象的列表,它們的目的和建議應如何使用它們來獲得最佳性能和用戶體驗。
FrameGrabberRecognizer是Blinkid SDK中最簡單的識別器,因為它沒有在給定的圖像上執行任何處理,而是將圖像返回其FrameCallback 。它的結果永遠不會從空的狀態改變狀態。
該識別器最適合使用RecognizerRunnerView輕鬆捕獲相機框架。請注意,發送到onFrameAvailable Image是暫時的,其內部緩衝區僅有效,直到onFrameAvailable方法執行 - 一旦方法結束,就可以處理Image對象的所有內部緩衝區。如果您需要存儲Image對像以備後用,則必須通過調用clone來創建它的副本。
還要注意, FrameCallback接口擴展了包裹可穿線的接口,這意味著在實現FrameCallback接口時,還必須實現Parcelable接口。
如果您計劃在活動之間傳輸FrameGrabberRecognizer ,這一點尤其重要 - 在這種情況下,請記住,您的對象的實例可能與調用onFrameAvailable方法的實例不一樣 - 調用onframeavailable方法的實例 - 接收onFrameAvailable接收的呼叫是在活動中創建的scAN的活動。
SuccessFrameGrabberRecognizer是一種特殊的Recognizer ,它包含其他Recognizer並在處理圖像時模仿它。但是,當Recognizer被冒充其Result變為Valid狀態時, SuccessFrameGrabberRecognizer捕獲了圖像並將其保存到其自身的Result對像中。
由於SuccessFrameGrabberRecognizer冒充了其奴隸Recognizer物對象,因此不可能將其包裹在同一RecognizerBundle bundle的混凝土Recognizer物對象和SuccessFrameGrabberRecognizer中,這樣做的結果將會具有相同的結果,就像您將兩個具有相同Recognizer類型的實例為RecognizerBundle類型一樣,它將崩潰您的應用程序。
當您需要捕獲其他Recognizer對像在其Result時處理的確切圖像時Valid此識別器最適合用例。當這種情況發生時, SuccessFrameGrabber's Result也將變得Valid ,並包含所描述的圖像。然後可以使用getSuccessFrame()方法檢索該圖像。
除非有具體識別器另有說明,否則該列表中的單側透明識別器可以在任何情況下使用,但它們最適合BlinkIdUISettings和DocumentScanUISettings ,並且UIS最適合文檔掃描。
合併的識別劑應與BlinkIdUISettings一起使用。他們管理單個相機打開的多個文檔側面的掃描,並引導用戶完成掃描過程。一些組合識別器支持掃描多種文檔類型,但一次只能掃描一種文檔類型。
BlinkIdSingleSideRecognizer掃描並從支持文檔的單一側提取數據。您可以在此處找到當前支持的文檔的列表。我們將通過在將來增加對新文檔類型的支持來繼續擴展這種識別器。播放此存儲庫以保持更新。
BlinkIdSingleSideRecognizer在BlinkIdUISettings和BlinkIdOverlayController中最有效。
使用BlinkIdMultiSideRecognizer掃描支持文檔的兩面。首先,它從正面掃描和提取數據,然後從背面掃描並提取數據,最後結合了兩側的結果。 BlinkIdMultiSideRecognizer還執行數據匹配並返回標誌,如果從前側捕獲的提取的數據與背面的數據匹配。您可以在此處找到當前支持的文檔的列表。我們將通過在將來增加對新文檔類型的支持來繼續擴展這種識別器。播放此存儲庫以保持更新。
BlinkIdMultiSideRecognizer在BlinkIdUISettings和BlinkIdOverlayController中最有效。
MrtdRecognizer用於從機器可讀區域(MRZ)掃描和數據提取各種機器可讀的旅行文檔(MRTD)(例如ID卡和護照)。此識別器不綁定到特定國家 /地區,但可以將其配置為返回與MrzFilter定義的一些標準相匹配的數據。
您可以在本節開頭找到有關用法上下文的信息。
掃描完整的文檔圖像和麵部圖像後, MrtdCombinedRecognizer掃描機讀取區(MRZ)(通常MRZ在後面,面部圖像在文檔的前側)。在內部,它使用DocumentFacerAgnizer獲取完整的文檔圖像和麵部圖像作為第一步,然後將MRTDRECOGNIZER掃描MRZ。
您可以在本節開頭找到有關用法上下文的信息。
PassportRecognizer用於從各種護照文檔的機器可讀區(MRZ)掃描和數據提取。此識別器還從護照中返回面部圖像。
您可以在本節開頭找到有關用法上下文的信息。
VisaRecognizer用於從各種簽證文檔的機器可讀區(MRZ)掃描和數據提取。此識別器還從簽證文檔返回面部圖像。
您可以在本節開頭找到有關用法上下文的信息。
IdBarcodeRecognizer用於掃描各種ID卡的條形碼。檢查此文檔以查看受支持的文檔類型的列表。
您可以在本節開頭找到有關用法上下文的信息。
DocumentFaceRecognizer是一種特殊類型的識別器,僅返回掃描文檔的臉部圖像和完整的文檔圖像。它不會提取文檔字段,例如名字,姓氏等。此通用識別器可用於在沒有某些文檔類型的特定支持的情況下獲取文檔圖像。
您可以在本節開頭找到有關用法上下文的信息。
您需要確保最終應用獲得Blinkid所需的所有資源。在撰寫本文檔時,Android不支持將多個AAR庫組合到單個Fat Aar中。問題是資源合併是在構建應用程序時而不是在構建AAR時完成的,因此應用程序必須意識到其所有依賴關係。沒有官方的Android方法可以在您的AAR中“隱藏”第三方AAR。
這個問題通常通過及時的Maven依賴性解決,即在發布您的AAR到Maven時,您指定了AAR的依賴項,因此使用AAR會自動引用它們。除此之外,您還可以嘗試其他幾種方法:
RecognizerRunnerView除外),嘗試避免此步驟。您可以在註意所有資源(字符串,佈局,圖像等)的同時執行自定義UI集成,僅來自AAR,而不是來自Blinkid 。然後,在您的AAR中,您不應參考LibBlinkID.aar作為Gradle依賴,相反,您應該解壓縮並將其資產複製到您的AAR資產文件夾,其類別,其classes.jar 。將其與AAR的LIB文件夾(應由Gradle引用為JAR依賴性),並將其JNI Folder的jni Folder的內容與AAR的SRC/Main/Main/Main/jnilibs colderibs andiribs colderib。Blinkid用ARMV7和ARM64本地圖書館二進製文件分發。
ARMV7架構使能夠利用硬件加速的浮點操作以及使用NEON進行SIMD處理。這為Blinkid帶來了具有ARMV7處理器的設備的巨大性能。大多數新設備(自2012年以來全部)都有ARMV7處理器,因此不利用這些處理器可以提供的性能提升是沒有意義的。另請注意,一些帶有ARMV7處理器的設備不支持NEON和VFPV4指令集,最受歡迎的是基於Nvidia Tegra 2,Arm Cortex A9及以上的設備。由於這些設備按照當今的標準是舊的,因此Blinkid不支持它們。出於同樣的原因, Blinkid不支持ARMV5( armeabi )架構的設備。
ARM64是大多數新設備使用的新處理器架構。 ARM64處理器非常強大,也有可能利用新的NEON64 SIMD指令集來快速使用單個指令處理多個像素。
有一些問題要考慮:
LibBlinkID.aar檔案包含本地圖書館的ARMV7和ARM64構建。默認情況下,當您將Blinkid集成到應用程序中時,您的應用程序將包含所有這些處理器體系結構的本機構建。因此, Blinkid將在ARMV7和ARM64設備上使用,並將在ARMV7設備和ARM64設備上使用ARMV7功能。但是,您的應用程序的大小將很大。
我們建議您使用應用程序捆綁包分發應用程序。這將將APK生成推遲到Google Play,從而使其可以為下載您的應用程序的每個特定設備生成最小的APK,包括僅需所需的處理器體系結構支持。
如果您無法使用應用程序捆綁包,則可以創建應用程序的多種口味 - 每種架構的一種風味。借助Gradle和Android Studio,這很容易 - 只需build.gradle以下代碼。
android {
...
splits {
abi {
enable true
reset()
include 'armeabi-v7a', 'arm64-v8a'
universalApk true
}
}
}
通過該構建說明,Gradle將為您的應用構建兩個不同的APK文件。每個APK將僅包含一個用於一個處理器體系結構的本機庫,一個APK將包含所有架構。為了使Google Play接受同一應用的多個APK,您需要確保每個APK都有不同的版本代碼。可以通過定義依賴架構的版本代碼前綴並在以下gradle腳本中添加真實版本代碼編號來輕鬆完成這一點:
// map for the version code
def abiVersionCodes = ['armeabi-v7a':1, 'arm64-v8a':2]
import com.android.build.OutputFile
android.applicationVariants.all { variant ->
// assign different version code for each output
variant.outputs.each { output ->
def filter = output.getFilter(OutputFile.ABI)
if(filter != null) {
output.versionCodeOverride = abiVersionCodes.get(output.getFilter(OutputFile.ABI)) * 1000000 + android.defaultConfig.versionCode
}
}
}
有關與Gradle創建APK拆分的更多信息,請查看Google的這篇文章。
生成多個APK之後,您需要將它們上傳到Google Play。有關教程和有關將多個APK上傳到Google Play的規則,請閱讀有關多個APK的官方Google文章。
如果您不會通過Google Play分發應用程序,或者出於某些其他原因希望擁有較小尺寸的單個APK,則可以從APK中完全刪除對某些CPU架構的支持。由於後果,不建議這樣做。
為了僅保留一些CPU架構,例如armeabi-v7a和arm64-v8a , android在build.gradle中添加以下語句。
android {
...
ndk {
// Tells Gradle to package the following ABIs into your application
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
這將刪除應用程序使用的所有本機庫的其他架構構建。
要刪除僅對Blinkid android某個CPU體系結構的支持,請在build.gradle中添加以下語句:Gradle:
android {
...
packagingOptions {
exclude 'lib/<ABI>/libBlinkID.so'
}
}
其中<ABI>表示您要刪除的CPU體系結構:
exclude 'lib/armeabi-v7a/libBlinkID.so'exclude 'lib/arm64-v8a/libBlinkID.so'您還可以通過多次exclude指令來刪除多個處理器架構。請記住,刪除處理器體系結構將對應用程序的性能和穩定性產生副作用。請閱讀此信息以獲取更多信息。
Google決定,截至2019年8月,Google Play上包含本機代碼的所有應用都需要為64位處理器提供本機支持(其中包括ARM64和X86_64)。這意味著您無法將應用程序上傳到僅支持32位ABI並且不支持相應64位ABI的Google Play Console。
通過刪除ARMV7支持, Blinkid將無法在具有ARMV7處理器的設備上工作。
通過刪除ARM64支持, Blinkid不會在ARM64設備上使用ARM64功能
如果將Blinkid庫與其他包含本機代碼的庫相結合到您的應用程序中,請確保與所有本機庫的架構匹配。例如,如果第三方庫只有ARMV7版本,則必須與該庫的Blinkid完全使用ARMV7版本,但不要使用ARM64。使用此架構將在初始化步驟中崩潰您的應用程序,因為JVM會嘗試將其所有本機依賴項加載到相同的首選體系結構中,並且會在UnsatisfiedLinkError Linkerror中失敗。
libc++_shared.so衝突。 Blinkid包含取決於C ++運行時的本機代碼。此運行時由libc++_shared.so提供,它需要在使用BlinkID的應用中可用。但是,包含本機組件的其他各種庫也使用了相同的文件。如果您碰巧將兩個庫與應用程序中的Blinkid一起集成在一起,則您的構建將失敗,與此類似的錯誤失敗:
* What went wrong:
Execution failed for task ':app:mergeDebugNativeLibs'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.MergeJavaResWorkAction
> 2 files found with path 'lib/arm64-v8a/libc++_shared.so' from inputs:
- <path>/.gradle/caches/transforms-3/3d428f9141586beb8805ce57f97bedda/transformed/jetified-opencv-4.5.3.0/jni/arm64-v8a/libc++_shared.so
- <path>/.gradle/caches/transforms-3/609476a082a81bd7af00fd16a991ee43/transformed/jetified-blinkid-6.12.0/jni/arm64-v8a/libc++_shared.so
If you are using jniLibs and CMake IMPORTED targets, see
https://developer.android.com/r/tools/jniLibs-vs-imported-targets
錯誤指出,多個不同的依賴關係提供了相同的文件lib/arm64/libc++_shared.so (在這種情況下為opencv和blinkid)。
您可以通過確保使用libc ++ _共享build.gradle libc++_shared.so新版本的依賴項來解決此問題。
android {
packaging {
jniLibs {
pickFirsts.add("lib/armeabi-v7a/libc++_shared.so")
pickFirsts.add("lib/arm64-v8a/libc++_shared.so")
}
}
}
重要說明
上面的代碼將始終從您的依賴項列表中選擇第一個libc++_shared.so因此,請確保使用libc++_shared.so的最新版本的依賴項首先列出。這是因為libc++_shared.so是向後兼容的,但不向前兼容。這意味著,例如libBlinkID.so libc++_shared.so libc ++ libc++_shared.so libc++_shared.so構建。對於您所有的本地依賴性,都是如此。
如果存在SDK集成問題,請首先確保您遵循集成說明。如果您仍然有問題,請通過help.microblink.com與我們聯繫。
如果您遇到“無效的許可證密鑰”錯誤或遇到其他與許可證有關的問題(例如,不應該啟用某些功能,或者在相機頂部有水印),請先檢查ADB LogCat。所有與許可有關的問題都記錄在錯誤日誌中,因此很容易確定出了什麼問題。
當您必須確定什麼是許可證問題或根本不理解日誌時,您應該與我們聯繫。Microblink.com。與我們聯繫時,請確保您提供以下信息:
AndroidManifest.xml和/或您的build.gradle文件)請記住:版本5.8.0及更高版本需要在我們的新許可管理計劃下進行互聯網連接。
我們只要求您這樣做,以便我們可以驗證您的試用許可證密鑰。數據提取仍然在設備本身上離線發生。驗證完成後,您可以在離線模式(或專用網絡上)繼續使用SDK,直到下一次檢查。
如果您在掃描某些項目時遇到問題,特定設備上的不希望的行為,在Blinkid內部崩潰或任何未提及的內容,請執行以下操作:
啟用記錄能夠看到庫在做什麼。要啟用日誌記錄,請將此行放入您的應用程序:
com . microblink . blinkid . util . Log . setLogLevel ( com . microblink . blinkid . util . Log . LogLevel . LOG_VERBOSE );在此行之後,庫將顯示有關其工作的盡可能多的信息。請將整個掃描會話的日誌保存到您將發送給我們的文件中。發送整個日誌非常重要,而不僅僅是發生崩潰的部分,因為崩潰有時是由圖書館初始化的早期階段出現的意外行為引起的。
通過help.microblink.com與我們聯繫,描述您的問題並提供以下信息:
Recognizer對象時,我將獲得InvalidLicenseKeyException每個許可證密鑰都包含有關允許使用哪些功能且不使用哪些功能的信息。此例外表明您的生產許可不允許使用特定的Recognizer對象。您應該聯繫支持,以檢查是否可以進行許可,並且它確實包含您購買的所有功能。
InvalidLicenseKeyException每當您構造任何Recognizer對像或任何從Entity派生的對象時,都會檢查許可證是否允許使用該對象。如果未在構造該對象之前設置許可證,則將獲得InvalidLicenseKeyException 。 We recommend setting license as early as possible in your app, ideally in onCreate callback of your Application singleton.
ClassNotFoundExceptionThis usually happens when you perform integration into Eclipse project and you forget to add resources or native libraries into the project. You must alway take care that same versions of both resources, assets, java library and native libraries are used in combination. Combining different versions of resources, assets, java and native libraries will trigger crash in SDK. This problem can also occur when you have performed improper integration of BlinkID SDK into your SDK. Please read how to embed BlinkID inside another SDK.
UnsatisfiedLinkError This error happens when JVM fails to load some native method from native library If performing integration into Android studio and this error happens, make sure that you have correctly combined BlinkID SDK with third party SDKs that contain native code, especially if you need resolving conflict over libc++_shared.so . If this error also happens in our integration sample apps, then it may indicate a bug in the SDK that is manifested on specific device. Please report that to our support team.
libc++_shared.so Please consult the section about resolving libc++_shared.so conflict.
MetadataCallbacks object, but it is not being called Make sure that after adding your callback to MetadataCallbacks you have applied changes to RecognizerRunnerView or RecognizerRunner as described in this section.
MetadataCallbacks object, and now app is crashing with NullPointerException Make sure that after removing your callback from MetadataCallbacks you have applied changes to RecognizerRunnerView or RecognizerRunner as described in this section.
onScanningDone callback I have the result inside my Recognizer , but when scanning activity finishes, the result is gone This usually happens when using RecognizerRunnerView and forgetting to pause the RecognizerRunnerView in your onScanningDone callback. Then, as soon as onScanningDone happens, the result is mutated or reset by additional processing that Recognizer performs in the time between end of your onScanningDone callback and actual finishing of the scanning activity. For more information about statefulness of the Recognizer objects, check this section.
IllegalStateException stating Data cannot be saved to intent because its size exceeds intent limit . This usually happens when you use Recognizer that produces image or similar large object inside its Result and that object exceeds the Android intent transaction limit. You should enable different intent data transfer mode. For more information about this, check this section. Also, instead of using built-in activity, you can use RecognizerRunnerFragment with built-in scanning overlay.
This usually happens when you attempt to transfer standalone Result that contains images or similar large objects via Intent and the size of the object exceeds Android intent transaction limit. Depending on the device, you will get either TransactionTooLargeException, a simple message BINDER TRANSACTION FAILED in log and your app will freeze or your app will get into restart loop. We recommend that you use RecognizerBundle and its API for sending Recognizer objects via Intent in a more safe manner (check this section for more information). However, if you really need to transfer standalone Result object (eg Result object obtained by cloning Result object owned by specific Recognizer object), you need to do that using global variables or singletons within your application. Sending large objects via Intent is not supported by Android.
Direct API When automatic scanning of camera frames with our camera management is used (provided camera overlays or direct usage of RecognizerRunnerView ), we use a stream of video frames and send multiple images to the recognition to boost reading accuracy. Also, we perform frame quality analysis and combine scanning results from multiple camera frames. On the other hand, when you are using the Direct API with a single image per document side, we cannot combine multiple images. We do our best to extract as much information as possible from that image. In some cases, when the quality of the input image is not good enough, for example, when the image is blurred or when glare is present, we are not able to successfully read the document.
Online trial licenses require a public network access for validation purposes. See Licensing issues.
onOcrResult() method in my OcrCallback is never invoked and all Result objects always return null in their OCR result gettersIn order to be able to obtain raw OCR result, which contains locations of each character, its value and its alternatives, you need to have a license that allows that. By default, licenses do not allow exposing raw OCR results in public API. If you really need that, please contact us and explain your use case.
You can find BlinkID SDK size report for all supported ABIs here.
Complete API reference can be found in Javadoc.
For any other questions, feel free to contact us at help.microblink.com.