{"id":2450,"date":"2024-11-05T11:45:10","date_gmt":"2024-11-05T02:45:10","guid":{"rendered":"http:\/\/blog.moramcnt.com\/?p=2450"},"modified":"2024-11-05T11:46:37","modified_gmt":"2024-11-05T02:46:37","slug":"react-native-voice%ec%9d%8c%ec%84%b1%ec%9d%b8%ec%8b%9d-%ec%82%ac%ec%9a%a9","status":"publish","type":"post","link":"http:\/\/blog.moramcnt.com\/?p=2450","title":{"rendered":"React Native Voice(\uc74c\uc131\uc778\uc2dd) \uc0ac\uc6a9"},"content":{"rendered":"<p><strong>I.\ubaa9\ud45c<\/strong><\/p>\n<p>\uc571\uc0c1\uc5d0\uc11c \uc8fc\uc18c\uac80\uc0c9\ub4f1\uc758 \ud654\uba74\uc5d0 \uc74c\uc131\uc778\uc2dd \uae30\ub2a5\uc744 \ucd94\uac00\ud558\uc5ec \ud3b8\ub9ac\uc131\uc744 \ud5a5\uc0c1\uc2dc\ud0a4\ub824\uace0 \ud55c\ub2e4.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>II. \uc5f0\uad6c\ubc0f \uac1c\ubc1c\ub0b4\uc6a9<\/strong><\/p>\n<p>1. \uc124\uce58<\/p>\n<table style=\"width: 100%; border-style: solid; border-color: #eeeeee; background-color: #ebebeb;\" border=\"0\">\n<tbody>\n<tr>\n<td>npm i @react-native-voice\/voice &#8211;save<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>2. \uc0ac\uc6a9\ubc29\ubc95<\/p>\n<p>&nbsp;<\/p>\n<table style=\"width: 100%; border-style: solid; border-color: #eeeeee; background-color: #ebebeb;\">\n<tbody>\n<tr>\n<td>import Voice from &#8220;@react-native-voice\/voice&#8221;;<\/p>\n<p>class AddrSearch extends PureComponent<\/p>\n<p>{<\/p>\n<p>constructor(props)<\/p>\n<p>{<\/p>\n<p>super(props);<\/p>\n<p>&nbsp;<\/p>\n<p>this.state = {<\/p>\n<p>title\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : &#8220;&#8221;,<\/p>\n<p>voiceStat\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : &#8220;&#8221;<\/p>\n<p>};<\/p>\n<p>Voice.onSpeechStart\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = this.onSpeechStart;<\/p>\n<p>Voice.onSpeechEnd\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = this.onSpeechEnd;<\/p>\n<p>Voice.onSpeechError\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = this.onSpeechError;<\/p>\n<p>Voice.onSpeechRecognized\u00a0\u00a0\u00a0 = this.onSpeechRecognized;<\/p>\n<p>Voice.onSpeechResults\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = this.onSpeechResults;<\/p>\n<p>this.mClsVoiceTimer\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = null;<\/p>\n<p>}<\/p>\n<p>\/**<\/p>\n<p>* componentDidMount \uc774\ubca4\ud2b8<\/p>\n<p>*\/<\/p>\n<p>componentDidMount()<\/p>\n<p>{<\/p>\n<p>\/\/ \uc74c\uc11d\uc778\uc2dd \uc885\ub8cc \ud0c0\uc774\uba38<\/p>\n<p>this.mClsVoiceTimer = new mosaic.timer.TimerMgr();<\/p>\n<p>this.mClsVoiceTimer.setInterval(5000);\u00a0 \/\/ 5\ucd08\ud6c4\uc5d0 \uc74c\uc131\uc778\uc2dd \uc885\ub8cc<\/p>\n<p>this.mClsVoiceTimer.addTickHandler(()=&gt; {<\/p>\n<p>console.log(&#8220;\ud0c0\uc774\uba38 \ub8e8\ud2f4&#8221;);<\/p>\n<p>this.doStopVoice();\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ \uc74c\uc11d\uc778\uc2dd \uc885\ub8cc<\/p>\n<p>this.doAddrSearch();\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ \uc8fc\uc18c \uac80\uc0c9<\/p>\n<p>});<\/p>\n<p>}<\/p>\n<p>\/**<\/p>\n<p>* componentWillUnmount \uc774\ubca4\ud2b8<\/p>\n<p>*\/<\/p>\n<p>componentWillUnmount()<\/p>\n<p>{<\/p>\n<p>Voice.destroy().then(Voice.removeAllListeners);<\/p>\n<p>if(this.mClsVoiceTimer != null)<\/p>\n<p>{<\/p>\n<p>this.mClsVoiceTimer.stop();<\/p>\n<p>this.mClsVoiceTimer = null;<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>doAddrSearch = () =&gt; {<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>doStartVoice = async() =&gt;<\/p>\n<p>{<\/p>\n<p>this.setState({ voiceStat: &#8220;\uc6d0\ud558\uc2dc\ub294 \uc8fc\uc18c\ub97c \ub9d0\uc500\ud574\uc8fc\uc138\uc694.&#8221; });<\/p>\n<p>this.mClsVoiceTimer.stop(); \/\/ \ud0c0\uc774\uba38 \uc885\ub8cc<\/p>\n<p>this.mClsVoiceTimer.start();<\/p>\n<p>try { await Voice.start(&#8220;ko-KR&#8221;); } catch (e) { console.error(e); }<\/p>\n<p>}<\/p>\n<p>doStopVoice = async() =&gt;<\/p>\n<p>{<\/p>\n<p>this.mClsVoiceTimer.stop(); \/\/ \ud0c0\uc774\uba38 \uc885\ub8cc<\/p>\n<p>try { await Voice.stop(); } catch (e) { console.error(e); }<\/p>\n<p>}<\/p>\n<p>onSpeechStart = (e) =&gt; {<\/p>\n<p>\/\/console.log(&#8220;onSpeechStart: &#8220;, e);<\/p>\n<p>this.setState({ voiceStat: &#8220;\uc74c\uc131\uc778\uc2dd\uc744 \uc2dc\uc791\ud558\uc600\uc2b5\ub2c8\ub2e4.&#8221; });<\/p>\n<p>};<\/p>\n<p>&nbsp;<\/p>\n<p>onSpeechEnd = (e) =&gt; {<\/p>\n<p>console.log(&#8220;onSpeechEnd: &#8220;, e);<\/p>\n<p>this.setState({voiceStat : &#8220;&#8221; });<\/p>\n<p>};<\/p>\n<p>onSpeechError = (e) =&gt; {<\/p>\n<p>console.log(&#8220;onSpeechError: &#8220;, e);<\/p>\n<p>if(e.error.code != 5)<\/p>\n<p>{<\/p>\n<p>\/\/ {&#8220;error&#8221;: {&#8220;code&#8221;: &#8220;5&#8221;, &#8220;message&#8221;: &#8220;5\/Client side error&#8221;}} \uac00 \uc544\ub2cc \uacbd\uc6b0\ub9cc \ucd9c\ub825<\/p>\n<p>this.setState({ voiceStat : &#8220;\uc74c\uc131\uc778\uc2dd\uc5d0 \uc2e4\ud328\ud558\uc600\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud558\uc5ec \uc8fc\uc138\uc694.&#8221;});<\/p>\n<p>}<\/p>\n<p>};<\/p>\n<p>onSpeechRecognized = (e) =&gt; {<\/p>\n<p>\/\/console.log(&#8220;onSpeechRecognized: &#8220;, e);<\/p>\n<p>this.setState({ voiceStat: &#8220;\uc74c\uc131\uc778\uc2dd\uc774 \ub418\uc5c8\uc2b5\ub2c8\ub2e4.&#8221; });<\/p>\n<p>};<\/p>\n<p>onSpeechResults = async(e) =&gt; {<\/p>\n<p>console.log(&#8221; \uc74c\uc131\uc778\uc2dd\uacb0\uacfc: &#8220;, e);<\/p>\n<p>let arrData = e.value;<\/p>\n<p>if(arrData.length &gt; 0)<\/p>\n<p>{<\/p>\n<p>this.setState({voiceStat: &#8220;&#8221;, searchValue : arrData[0]}, ()=&gt;{<\/p>\n<p>this.doAddrSearch();<\/p>\n<p>});<\/p>\n<p>}<\/p>\n<p>};<\/p>\n<p>\/**<\/p>\n<p>* \ud654\uba74 \ub80c\ub354<\/p>\n<p>*\/<\/p>\n<p>render()<\/p>\n<p>{<\/p>\n<p>const {title, voiceStat} = this.state<\/p>\n<p>return (<\/p>\n<p>&lt;BottomSheetView style={baseStyle.bottomSheetBox}&gt;<\/p>\n<p>&lt;View style={baseStyle.bottomSheetBoxBody}&gt;<\/p>\n<p>&lt;View style={baseStyle.bottomSheetBoxBodyTitH3}&gt;<\/p>\n<p>&lt;Text style={baseStyle.bottomSheetTitH3}&gt;&lt;Text style={baseStyle.bottomSheetTitBoldH3}&gt;\uc8fc\uc18c&lt;\/Text&gt;\uac80\uc0c9&lt;\/Text&gt;<\/p>\n<p>&lt;\/View&gt;<\/p>\n<p>&lt;View style={{position:&#8221;relative&#8221;, width:&#8221;100%&#8221;, alignItems:&#8221;center&#8221;, paddingHorizontal:15, paddingTop:10, paddingBottom:5 }}&gt;<\/p>\n<p>&lt;View style={{ width: &#8220;100%&#8221;, backgroundColor:&#8221;#f3f3f3&#8243;, borderRadius:10, justifyContent:&#8221;center&#8221;}}&gt;<\/p>\n<p>&lt;TextInput<\/p>\n<p>style={{paddingVertical:13, paddingHorizontal:15, fontSize:fonts.getFontSize(15, this.props.appData), fontWeight:&#8221;400&#8243;, color: colors.PLACEHOLDER, fontFamily:fonts.GMARKET_MEDIUM }}<\/p>\n<p>numberOfLines={1}<\/p>\n<p>autoCorrect={false}<\/p>\n<p>underlineColorAndroid={&#8220;transparent&#8221;}<\/p>\n<p>placeholder={&#8220;\uc8fc\uc18c\ub098 \uac74\ubb3c \uc774\ub984\uc744 \uc785\ub825\ud558\uc138\uc694&#8221;}<\/p>\n<p>placeholderTextColor={colors.PLACEHOLDER}<\/p>\n<p>returnKeyType={&#8220;search&#8221;}<\/p>\n<p>onChangeText={(strText) =&gt; this.setState({ searchValue: strText })}<\/p>\n<p>value={this.state.searchValue}<\/p>\n<p>onSubmitEditing={this.doAddrSearch}\/&gt;<\/p>\n<p>&lt;TouchableOpacity style={{position:&#8221;absolute&#8221;, right: 35, paddingVertical:10, paddingHorizontal:10 }} activeOpacity={0.6} onPress={this.doAddrSearch}&gt;<\/p>\n<p>&lt;IconFa6 name=&#8221;magnifying-glass&#8221; solid style={{fontSize: fonts.getFontSize(22, this.props.appData), fontWeight:&#8221;700&#8243;, opacity:0.7, color: colors.PLACEHOLDER}} \/&gt;<\/p>\n<p>&lt;\/TouchableOpacity&gt;<\/p>\n<p>&lt;TouchableOpacity style={{position:&#8221;absolute&#8221;, right: 0, paddingVertical:10, paddingHorizontal:10 }} activeOpacity={0.6} onPress={this.doStartVoice}&gt;<\/p>\n<p>&lt;IconFa6 name=&#8221;microphone&#8221; solid style={{fontSize: fonts.getFontSize(22, this.props.appData), fontWeight:&#8221;700&#8243;, opacity:0.7, color: colors.DARK}} \/&gt;<\/p>\n<p>&lt;\/TouchableOpacity&gt;<\/p>\n<p>&lt;\/View&gt;<\/p>\n<p>&lt;\/View&gt;<\/p>\n<p>&lt;View style={{position:&#8221;relative&#8221;, width:&#8221;100%&#8221;, alignItems:&#8221;center&#8221;, paddingHorizontal:10, paddingTop:5, paddingBottom:5, }}&gt;<\/p>\n<p>&lt;Text style={{color: colors.PRIMARY, padding:0, fontSize: fonts.getFontSize(13, this.props.appData), fontWeight:&#8221;bold&#8221;, fontFamily: fonts.NANUNM_REGULAR}}&gt;{voiceStat}&lt;\/Text&gt;<\/p>\n<p>&lt;\/View&gt;<\/p>\n<p>&lt;View style={{width: (width &#8211; 40), flex:1 }}&gt;<\/p>\n<p>&lt;FlatList<\/p>\n<p>data={this.state.addrLocation}<\/p>\n<p>keyExtractor={item =&gt; item.addrSeq.toString()}<\/p>\n<p>renderItem={this.renderItem}<\/p>\n<p>contentContainerStyle={{backgroundColor: colors.WHITE}}<\/p>\n<p>ListEmptyComponent={this.renderNoDataItem}<\/p>\n<p>\/&gt;<\/p>\n<p>&lt;\/View&gt;<\/p>\n<p>&lt;\/View&gt;<\/p>\n<p>&lt;\/BottomSheetView&gt;<\/p>\n<p>);<\/p>\n<p>}<\/p>\n<p>}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p><strong>III. \uacb0\ub860<\/strong><\/p>\n<p>\uac00\ub054\uc529\u00a0 onSpeechError\ub85c \uc624\ub958\uac00 \ub9ac\ud134\ub418\uc5b4, \uc544\ub798\uc640 \uac19\uc774 code\uac00 5\ubc88\uc778 \uacbd\uc6b0\ub294 \uc81c\uc678\ud558\uace0 \ubcf4\uc5ec\uc8fc\ub3c4\ub85d \ud558\uc600\ub2e4.<\/p>\n<p>{&#8220;error&#8221;: {&#8220;code&#8221;: &#8220;5&#8221;, &#8220;message&#8221;: &#8220;5\/Client side error&#8221;}}<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I.\ubaa9\ud45c \uc571\uc0c1\uc5d0\uc11c \uc8fc\uc18c\uac80\uc0c9\ub4f1\uc758 \ud654\uba74\uc5d0 \uc74c\uc131\uc778\uc2dd \uae30\ub2a5\uc744 \ucd94\uac00\ud558\uc5ec \ud3b8\ub9ac\uc131\uc744 \ud5a5\uc0c1\uc2dc\ud0a4\ub824\uace0 \ud55c\ub2e4. &nbsp; II. \uc5f0\uad6c\ubc0f \uac1c\ubc1c\ub0b4\uc6a9 1. \uc124\uce58 npm i @react-native-voice\/voice &#8211;save 2. \uc0ac\uc6a9\ubc29\ubc95 &nbsp; import Voice from &#8220;@react-native-voice\/voice&#8221;; class AddrSearch extends PureComponent { constructor(props) { super(props); &nbsp; this.state = { title\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : &#8220;&#8221;, voiceStat\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : &#8220;&#8221; }; Voice.onSpeechStart\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = this.onSpeechStart; Voice.onSpeechEnd\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = this.onSpeechEnd; Voice.onSpeechError\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = this.onSpeechError; [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[321,2],"tags":[322],"class_list":["post-2450","post","type-post","status-publish","format-standard","hentry","category-react-natvie","category-2","tag-react-native-voice-"],"_links":{"self":[{"href":"http:\/\/blog.moramcnt.com\/index.php?rest_route=\/wp\/v2\/posts\/2450","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.moramcnt.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.moramcnt.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.moramcnt.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.moramcnt.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2450"}],"version-history":[{"count":1,"href":"http:\/\/blog.moramcnt.com\/index.php?rest_route=\/wp\/v2\/posts\/2450\/revisions"}],"predecessor-version":[{"id":2451,"href":"http:\/\/blog.moramcnt.com\/index.php?rest_route=\/wp\/v2\/posts\/2450\/revisions\/2451"}],"wp:attachment":[{"href":"http:\/\/blog.moramcnt.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2450"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.moramcnt.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2450"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.moramcnt.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2450"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}