나는 첫 번째 CSS : 호버 효과를 만든 순간 코딩에 사랑에 빠졌다. 몇 년 후, 웹에서의 상호 작용에 대한 초기 물기는 새로운 목표, 즉 게임 만들기로 이어졌습니다.
그 이른 순간과 함께하는 순간 : 호버는 특별하거나 유용하지 않았습니다. 나는 파란색 사각형의 반응 형 그리드를 만든 것을 기억합니다 (플로트로 만든 타임 라인에 대한 아이디어를 제공한다면). 나는 상자 위에 욕을당하는 시간을 보냈고, 창을 조화하여 크기와 정렬을 바꾸는 것을 보았다. 순수한 마술처럼 느껴졌습니다.
내가 웹에서 구축 한 것은 자연스럽게 수년에 걸쳐
때때로 그것은 단지 Codepen 데모였습니다. 때로는 Vercel 또는 NetLify에 배치 된 작은 측면 프로젝트였습니다. 나는 컬러 홍수, 행맨 또는 브라우저에서 4 개의 연결과 같은 게임을 재현하는 도전을 좋아했습니다.
하지만 잠시 후 목표가 커졌습니다. 실제 게임을 하면 어떻게 될까요 ? 웹 앱뿐만 아니라; 진정한 라이브, 정직한 선수, app-app-store 게임에서 다운로드. 지난 8 월, 나는 지금까지 가장 야심 찬 프로젝트를 시작했고, 4 개월 후, 나는 그것을 세계에 공개했습니다 ( 읽기 : 피곤한 것에 지쳤습니다 ) : Quina라고 부르는 단어 게임 앱.
Quina를 설명하는 가장 쉬운 방법은 : 마스터 마인드이지만 5 글자 단어가 있습니다. 사실, Mastermind는 실제로 클래식 펜 앤 페이퍼 게임의 버전입니다. Quina는 단순히 동일한 원본 게임의 또 다른 변형입니다.
Quina의 대상은 비밀 5 글자 단어를 추측하는 것입니다. 각 추측 후에, 당신은 코드 단어에 당신의 추측이 얼마나 가까운 지 알려주는 단서를 얻습니다. 당신은 그 단서를 사용하여 다음 추측을 세분화하지만, 당신은 총 10 번의 추측 만 얻습니다. 도망 치면 잃습니다.
“Quina”라는 이름은 라틴어로 한 번에“5 씩”를 의미하기 때문에 나왔습니다 (또는 Google은 어쨌든 나에게 말했습니다). 전통적인 게임은 일반적으로 4 글자 단어 또는 때로는 4 자리 (또는 Mastermind의 경우 4 가지 색상)로 재생됩니다. Quina는 반복 된 글자가없는 5 글자 단어를 사용하므로 게임이 자체 규칙에 따라 재생되는 이름이 있어야한다고 생각했습니다. (원래의 라틴어 단어가 어떻게 발음되었는지는 모르겠지만, 아마도 "Quinn-ah"라고 말하지만 아마도 잘못되었지만, 내 게임입니다.)
나는 약 4 개월 동안 저녁과 주말을 앱을 만들었습니다. 나는이 기사에 게임 뒤의 기술, 관련된 결정, 그리고 배운 교훈에 대해이 기사에 대해 이야기하고 싶습니다.
저는 Vue의 열렬한 팬 이며이 프로젝트를 생태계에 대한 지식을 확장하는 방법으로 사용하고 싶었습니다. 나는 다른 프레임 워크를 사용하는 것을 고려했지만 (또한 Svelte and React에서 프로젝트를 구축했습니다), 나는 Nuxt가 친숙 함, 사용 편의성 및 성숙의 달콤한 지점에 부딪쳤다 고 느꼈습니다. (그건 그렇고, 당신이 알지 못했거나 짐작하지 않았다면 : nuxt는 다음에 vue와 동등한 Vue로 묘사 될 수 있습니다.
나는 이전에 nuxt와 너무 깊이 가지 않았다. 아주 작은 앱 몇 개뿐입니다. 그러나 NUXT가 정적 앱으로 컴파일 할 수 있다는 것을 알았습니다.이 앱은 제가 원하는 것입니다. 또한 NUXT가 VUE 구성 요소를 /페이지 폴더로 삭제하는 것만 큼 쉽게 라우팅을 처리 할 수 있다는 것을 알고있었습니다.
또한 Vuex (VUE의 공식 국가 관리)는 그 자체로는 매우 복잡하지는 않지만 Nuxt가 설탕을 약간 추가하여 더 단순하게 만드는 방식에 감사했습니다. (NUXT는 구성 요소를 사용하기 전에 명시 적으로 가져 오는 것을 필요로하지 않는 등 다양한 방식으로 일을 쉽게 할 수있게합니다. 마크 업에 넣을 수 있으며 NUXT는 그것을 알아 내고 필요에 따라 자동 임금을 내게 할 수 있습니다.
마지막으로, 나는 PWA (Progressive Web App)을 구축하고 있다는 것을 미리 알았으므로 이미 포장되어 있고 준비가 된 모든 기능 (오프라인 기능을위한 서비스 작업자와 같은 모든 기능)을 구축하는 데 도움이되는 NUXT PWA 모듈이 이미 있다는 사실은 이미 큰 추첨이었습니다. 실제로 보이지 않는 장애물에 사용할 수있는 인상적인 NUXT 모듈이 있습니다. 그것은 Nuxt를 가장 쉽고 가장 명백한 선택으로 만들었고, 결코 후회하지 않았습니다.
Markdown에서 페이지 컨텐츠를 작성하거나 Markdown 및 VUE 구성 요소의 혼합물을 작성할 수있는 Stellar Nuxt 컨텐츠 모듈을 포함하여 더 많은 모듈을 사용하게되었습니다. 나는 "FAQS"페이지와 "Mow To Play"페이지 에도이 기능을 사용했습니다 (Markdown에 쓰는 것이 하드 코딩 HTML 페이지보다 훨씬 좋습니다).
Quina는 결국 Google Play 스토어에서 집을 찾을 것이지만, 어떻게 또는 어디에서 플레이했는지에 관계없이 Get-Go에서 본격적인 앱처럼 느껴지 기를 원했습니다.
우선, 선택적인 다크 모드와 많은 기본 앱과 마찬가지로 최적의 유용성을위한 모션을 줄이기위한 설정을 의미했습니다 (애니메이션이 있는 것과 마찬가지로 동작이 줄어드는 경우).
후드 아래에서 두 설정은 궁극적으로 앱의 vuex 데이터 저장소에서 부울입니다. 사실 인 경우 설정은 앱의 기본 레이아웃에서 특정 클래스를 렌더링합니다. NUXT 레이아웃은 모든 컨텐츠를 "랩"하고 앱의 모든 (또는 많은) 페이지를 렌더링하는 Vue 템플릿입니다 (공유 헤더 및 바닥 글과 같은 것에 일반적으로 사용되지만 글로벌 설정에도 유용합니다).
<emplate> <div :> <nuxt></nuxt> </div> 템플릿> <cript> 'vuex'에서 {mapgetters} 가져 오기 내보내기 기본값 { 계산 : { ... MapGetters ([ 'DarkMode', 'RedeMotion']), }, // 다른 레이아웃 구성 요소 코드는 여기에 있습니다 } 스크립트></cript></emplate>
설정에 대해 : 웹 앱은 메뉴, 설정, 소개, 재생 등 여러 페이지로 분할되지만 공유 된 Global Vuex Data Store는 앱 영역간에 물건을 동기화하고 원활하게 느끼는 데 도움이됩니다 (사용자는 한 페이지에서 설정을 조정하고 다른 페이지에서 게임에 적용되는 것을 보았습니다).
앱의 모든 설정은 사용자가 페이지간에 탐색 할 때 설정을 추적하는 것 외에 세션간에 값을 저장하고로드 할 수있는 LocalStorage 및 Vuex 스토어와 동기화됩니다.
그리고 내비게이션에 관해 말하기 : 페이지 사이를 이동하는 것은 전체 페이지 전환을 추가하여 Quina가 기본 앱처럼 느낄 수있는 기회가 많다고 생각하는 또 다른 영역입니다.
Vue 전환은 일반적으로 상당히 간단합니다.“To”및“From”전환 상태에 대해 특별히 이름 지정된 CSS 클래스를 작성하지만 NUXT는 한 단계 더 나아가 페이지의 VUE 파일에서 단일 줄만으로 전체 페이지 전환을 설정할 수 있습니다.
<cript> 내보내기 기본값 { 전환 : '페이지 슬라이드' // ... 나머지 구성 요소 속성 } 스크립트></cript>
그 전환 속성은 강력합니다. 그것은 우리가 그것을 탐색 하거나 멀리 할 때마다 페이지 슬라이드 전환 이이 페이지에 적용되기를 원한다는 것을 알 수 있습니다. 거기에서 우리가해야 할 일은 VUE 전환과 마찬가지로 애니메이션을 처리하는 클래스를 정의하는 것입니다. 내 페이지 슬라이드 SCSS는 다음과 같습니다.
/ * 자산/css/_animations.scss */ .page-slide { & -Enter-Active { 전환 : 모든 0.35S 입방-베 지어 (0, 0.25, 0, 0.75); } & -leave-active { 전환 : 모든 0.35S 입방-베 지어 (0.75, 0, 1, 0.75); } &-입력하다, & -leave-to { 불투명도 : 0; 변환 : Translatey (1rem); .reduce-motion & { 변환 : 없음! 중요; } } & -leave-to { 변환 : Translatey (-1REM); } }
.reduce-motion 클래스에 주목하십시오. 그것이 바로 위의 레이아웃 파일에서 우리가 이야기 한 것입니다. 사용자가 변환 속성을 비활성화하여 (분열적인! 중요한 플래그의 사용을 보장하는 것처럼 보이는) 모션 감소 (미디어 쿼리 또는 수동 설정을 통해)를 선호한다고 표시했을 때 시각적 움직임을 방지합니다. 그러나 불투명도는 여전히 움직이지 않기 때문에 여전히 사라질 수 있습니다.
전환 및 처리 404 : 전환 및 라우팅은 물론 후드 아래에서 JavaScript에 의해 처리되지만 (Vue Router, 정확히 정확하게), 스크립트가 Idle 페이지에서 실행 중지를 중단하는 좌절 문제에 부딪쳤다 (예 : 사용자가 앱 또는 탭을 배경으로 열면). 유휴 페이지로 돌아와서 링크를 클릭하면 Vue Router는 실행이 중지되었을 것이므로 링크는 상대 및 404로 취급됩니다.
예 : /FAQ 페이지가 유휴 상태입니다. 사용자가 다시 와서 링크를 클릭하여 /옵션 페이지를 방문합니다. 앱은 /FAQ /옵션으로 이동하려고 시도 할 것입니다. 물론 존재하지 않습니다.
이에 대한 솔루션은 사용자 정의 오류입니다. vue 페이지 (이것은 모든 오류를 자동으로 처리하는 nuxt 페이지입니다), 여기서 들어오는 경로에서 유효성 검사를 실행하고 경로 끝까지 리디렉션합니다.
// 레이아웃/error.vue 마운트 () { const lastpage = '/'this. $ route.fullpath.split ( '/'). pop () // 리디렉션 루프를 생성하지 마십시오 if (lastpage! == this. $ route.fullPath) { 이. $ router.push ({{ 경로 : 마지막 페이지, }) } }
a) 중첩 경로가 없기 때문에 이것은 내 사용 사례에 효과가있었습니다. 그리고 b) 끝에서 경로가 유효하지 않으면 여전히 404에 부딪칩니다.
전환은 좋지만 Quina는 진동과 소리없이 스마트 폰에서 기본 앱처럼 느껴 지지 않을 것임도 알고있었습니다.
Navigator API 덕분에 요즘 브라우저에서 진동을 쉽게 달성 할 수 있습니다. 대부분의 최신 브라우저는 단순히 Window.navigator.vibrate ()를 호출하여 사용자에게 약간의 버즈 또는 일련의 버즈를 제공하거나 매우 짧은 기간을 사용하여 스마트 폰 키보드에서 키를 탭할 때와 같이 약간의 촉각 피드백을 제공합니다.
분명히, 당신은 몇 가지 이유로 진동을 드물게 사용하고 싶습니다. 첫째, 너무 많은 사람들이 쉽게 나쁜 사용자 경험이 될 수 있기 때문입니다. 둘째, 모든 장치/브라우저가이를 지원하는 것은 아니므로 현재 실행중인 스크립트를 종료하는 오류가 발생하지 않도록 Vibrate () 함수를 호출하려는 방법과 위치에 대해 매우 조심해야합니다.
개인적으로 내 해결책은 Vuex Getter를 설정하여 사용자가 진동을 허용하고 있는지 확인하는 것이 었습니다 (설정 페이지에서 비활성화 할 수 있음). 현재 컨텍스트는 서버가 아니라 클라이언트라는 것입니다. 마지막으로, 기능은 현재 브라우저에 존재합니다. (ES2020 옵션 체인은 그 마지막 부분을 위해 여기서도 작동했을 것입니다.)
// Store/Getters.js 진동 (상태) { 만약에 ( Process.Client&& state.options.vibration && typeof window.navigator.vibrate! == 'undefined' ) { 진실을 반환하십시오 } 거짓을 반환하십시오 },
참고 사항 : Process.Client를 확인하는 것은 Nuxt에서 중요하며, Window가 항상 존재하지 않기 때문에 노드에서 실행될 수있는 코드가있는 다른 많은 프레임 워크입니다. 구성 요소가 빌드 시간 동안 노드에서 검증되기 때문에 정적 모드에서 nuxt를 사용하더라도 마찬가지입니다. Process.Client (및 그 반대, Process.Server)는 런타임시 코드의 현재 환경을 검증하는 NUXT NICETIE이므로 브라우저 전용 코드를 격리하는 데 적합합니다.
Sound 는 앱 사용자 경험의 또 다른 핵심 부분입니다. 내 자신의 효과를내는 대신 (프로젝트에 수십 시간을 더 추가했을 것임), 나는 그 영역에서하고있는 일을 더 잘 알고 온라인에서 무료 게임 사운드를 제공 한 몇몇 아티스트의 샘플을 혼합했습니다. (전체 정보는 앱의 FAQ를 참조하십시오.)
사용자는 원하는 볼륨을 설정하거나 사운드를 완전히 닫을 수 있습니다. 이것은 또한 사용자의 브라우저의 LocalStorage에도 설정되어 Vuex 스토어와 동기화됩니다. 이 접근법을 사용하면 브라우저에 저장된 "영구적 인"설정을 설정할 수 있지만 참조 할 때마다 브라우저에서 검색 할 필요가 없습니다. (예를 들어, 사운드는 재생 될 때마다 현재 볼륨 레벨을 점검하고, 발생할 때마다 로컬 스토리지 호출 대기 시간이 경험을 죽이기에 충분할 수 있습니다.)
어떤 이유로 든 사파리는 소리에 관해 매우 느린 것으로 밝혀졌습니다. 모든 클릭, 부프 및 딩은 이벤트 이후 실제로 IOS에서 Safari에서 플레이하도록 유발 한 후 눈에 띄는 시간이 걸립니다. 그것은 거래를 중단하는 사람이었고 토끼 구멍은 절망적으로 터널링하는 시간을 많이 보냈습니다.
다행히도, 나는 Cross-Platform 사운드 문제를 아주 쉽게 해결하는 Howler.js라는 도서관을 발견했습니다 (그리고 재미있는 작은 로고도 있습니다). 하우러를 종속성으로 설치하고 기본적으로 하나 또는 두 줄의 코드 라인을 통해 앱의 모든 사운드를 실행하는 것만으로도 문제를 해결하기에 충분했습니다.
Safari의 문제가 무엇인지 또는 울부 짖는 소리가 어떻게 해결되는지 전혀 모르기 때문에 Howler를 사용하는 것이 좋습니다. 내가 시도한 것은 없었기 때문에 문제가 거의 오버 헤드 나 코드 수정으로 쉽게 해결되는 것이 행복합니다.
Quina는 특히 처음에는 어려운 게임이 될 수 있으므로 개인 선호도에 맞게 게임의 어려움을 조정하는 몇 가지 방법이 있습니다.
이 설정을 통해 다양한 기술, 나이 및/또는 영어 능력을 가진 플레이어는 자체 수준에서 게임을 할 수 있습니다. (강한 힌트가있는 기본 단어는 가장 쉬운 일입니다. 힌트가없는 까다 롭거나 무작위가 가장 어렵습니다.)
조절 가능한 난이도가있는 일련의 일회성 게임을 즐기는 것은 충분히 즐거울 수 있지만, 이는 실제 풀 링크 게임보다 표준 웹 앱이나 데모처럼 느껴질 것입니다. 따라서 Quina는 기본 앱 느낌을 추구하기 위해 게임 기록을 추적하고 다양한 방식으로 플레이 통계를 보여 주며 다양한 업적을위한 몇 가지“상”을 제공합니다.
후드 아래에서 각 게임은 다음과 같이 보이는 물체로 저장됩니다.
{ 추측 : 3, 난이도 : '까다로운', Win : True, 힌트 : '없음', }
이 앱은 게임을 재생 한 게임 (Vuex State를 통해 LocalStorage와 동기화)을 게임 히스토리 배열의 게임 객체 배열로 카탈로그합니다.이 게임은 승리/손실 비율, 플레이 한 게임 수 및 평균 추측과 같은 통계를 표시하는 데 사용합니다.
이것은 다양한 vuex getters에서 충분히 쉽게 수행되며, 각각은 게임 history 배열에서 .filter () 및 .reduce ()와 같은 JavaScript 배열 메소드를 사용합니다. 예를 들어, 이것은 "까다로운"설정에서 플레이하는 동안 사용자가 얼마나 많은 게임을 이겼는지 보여주는 게터입니다.
// Store/Getters.js trickygameswon (state) { return state.gamehistory.filter ( (게임) => game.win && game.difficulty === 'tricky' ).길이 },
다양한 복잡성의 다른 많은 getter가 있습니다. (사용자의 가장 긴 승리 행진을 결정하는 사람은 특히 어리석은 일이었습니다.)
상을 추가하는 것은 각각 특정 vuex getter와 관련이있는 수상한 개체를 만드는 문제였으며, 각각은 요구 사항이 있습니다. 어워드 속성은 해당 상이 잠금 해제 된시기를 나타냅니다 (즉, Getter가 반환 한 값이 충분히 높았을 때). 다음은 샘플입니다.
// 자산/JS/Awards.js 내보내기 기본값 [ { 제목 : '발병', 요구 사항: { Getter : 'TotalGamesPlayed', 임계 값 : 1, 텍스트 : 'Quina의 첫 번째 게임 재생', } }, { 제목 : 'Sharp', 요구 사항: { getter : 'trickygameswon', 임계 값 : 10, 텍스트 : '까다로운 총 게임 10 번 승리', }, }, ]]
여기에서 요구 사항을 사용하여 VUE 템플릿 파일의 업적을 반복하여 최종 출력을 가져 오기 위해 매우 간단한 문제입니다. 텍스트 속성 (수상을 달성하기위한 사용자의 진행 상황을 보여주기 위해 다양한 수학 및 애니메이션이 추가되어 있지만 :
특정 수의 게임에서 우승하거나 모든 게임 모드를 시험해 보거나 처음 세 가지 추측 내에서 게임에서 승리하는 등 다양한 업적에 대해 25 개의 상 (테마와 함께 5 × 5)이 있습니다. (그중 하나는“운이 좋은” - 작은 부활절 달걀로서, 각 상의 이름은 잠재적 인 코드 단어, 즉 반복이없는 5 개의 글자입니다.)
어워드 잠금 해제는 자랑하는 권리를 제공하는 것 외에는 아무것도하지 않지만 일부는 달성하기가 매우 어렵습니다. (그들을 모두 얻는 데 몇 주가 걸렸습니다!)
“한 번 빌드 한 번, 어디서나 배포”전략에 대해 사랑하는 것이 많지만 몇 가지 단점도 함께 제공됩니다.
“웹 빌드, 모든 곳에서 출시”약속을하는 많은 기술이 있습니다.
일반적으로 이들은 두 가지 범주로 요약됩니다.
첫 번째 접근법은 두 사람 중 더 바람직한 것처럼 보일 수 있습니다 (끝에서 모든 것이 이론적으로“실제”기본 앱으로 끝나기 때문에) 또한 가장 큰 장애물이 있습니다. 모든 플랫폼이나 제품은 일을하는 방식을 배워야하며, 그 방식은 전체 생태계와 프레임 워크 자체가되어야합니다. “당신이 아는 것을 쓰기”라는 약속은 내 경험에서 매우 강한 과장입니다. 1 년에서 2 년 안에 이러한 문제가 해결 될 것이라고 생각하지만 지금 당장은 여전히 웹 코드 작성과 기본 앱 배송 사이의 상당한 차이를 느낍니다.
반면에, 두 번째 접근 방식은 "TWA"라는 것이기 때문에 실행 가능합니다. 이는 웹 사이트를 처음부터 앱으로 만들 수 있습니다.
TWA는 신뢰할 수있는 웹 활동을 나타냅니다. 그리고 그 대답은 전혀 도움이되지 않기 때문에 조금 더 나쁘게 봅시다.
TWA 앱은 기본적으로 약간의 UI 속임수를 사용하여 웹 사이트 (또는 머리카락을 분할하려면)를 기본 앱으로 바꿉니다.
TWA 앱을 변장의 브라우저로 생각할 수 있습니다 . 웹 브라우저를 제외하고 내부가없는 Android 앱입니다. TWA 앱은 특정 웹 URL을 가리킬 수 있으며, 앱이 일반적인 기본 앱 작업을 수행하지 않고 앱을 부팅 할 때마다 해당 웹 사이트를 대신에로드하여 브라우저 컨트롤이없는 전체 화면을 적용하여 웹 사이트를 효과적으로 보이고 전체 플러드 네이티브 앱인 것처럼 작동합니다.
기본 앱에서 웹 사이트를 마무리하는 것은 쉽게 볼 수 있습니다. 그러나 이전 사이트 나 URL은 자격이 없습니다. 웹 사이트/앱을 TWA 기본 앱으로 시작하려면 다음 상자를 확인해야합니다.
마지막 요점은“신뢰할 수있는”부분이 들어오는 곳입니다. TWA 앱은 자체 키를 확인한 다음 웹 앱의 키가 일치하는지 확인하여 올바른 사이트를로드하는지 확인합니다 (아마도 앱 URL의 악의적 인 납치 방지). 키가 일치하지 않거나 찾을 수없는 경우 앱은 여전히 작동하지만 TWA 기능은 사라집니다. 웹 사이트를 일반 브라우저, Chrome 및 모두에로드합니다. 따라서 핵심은 앱 경험에 매우 중요합니다. (당신은 그것이 중요한 부분이라고 말할 수 있습니다. 죄송합니다.)
TWA 앱의 주요 장점은 코드를 전혀 변경할 필요가 없다는 것입니다 - 배울 프레임 워크 나 플랫폼이 없습니다. 당신은 단지 정상과 같은 웹 사이트/웹 앱을 구축하고 있으며, 일단 완료되면 기본적으로 앱 코드도 완료되었습니다.
그러나 주요 단점은 (웹 및 JavaScript의 현대를 안내하는 데 도움이 되었음에도 불구하고) Apple은 TWA 앱을 선호 하지 않는다는 것입니다. Apple App Store에 나열 할 수 없습니다. Google Play 만.
이것은 거래 차단기처럼 들릴지 모르지만 몇 가지를 염두에두고 있습니다.
이 시점 에서이 TWA 비즈니스는 모두 잘 들리지만 실제로 내 사이트/앱을 가져 와서 Android 앱으로 어떻게 전환합니까?
대답은 BubbleWrap이라는 사랑스러운 작은 CLI 도구의 형태로 제공됩니다.
BubbleWrap을 귀하의 입력 및 옵션을 취하는 도구로 생각하고 입력에서 Android 앱 (특히 Google Play 스토어에서 허용 파일 형식 중 하나)을 생성 할 수 있습니다.
BubbleWrap을 설치하는 것은 약간 까다로울 수 있으며, 사용하는 것은 플러그 앤 플레이가 아니지만, 내가 찾은 다른 비슷한 옵션보다 평균 프론트 엔드 데브의 범위 내에서 훨씬 더 많은 내용입니다. BubbleWrap의 NPM 페이지의 readme 파일은 세부 사항으로 이동하지만 간단한 개요는 다음과 같습니다.
npm i -g @bubblewrap/cli를 실행하여 Bubblewrap을 설치하십시오 (여기서는 NPM에 익숙하고 명령 줄을 통해 패키지를 설치한다고 가정합니다). 그것은 당신이 어디서나 버블 트랩을 사용할 수있게합니다.
설치되면 실행됩니다.
bubblewrap init-manifest https : //your-webapp-domain/manifest.json
참고 : Manifest.json 파일은 모든 PWA에 필요하며 BubbleWrap은 앱뿐만 아니라 해당 파일의 URL이 필요합니다. 또한 경고 : 매니페스트 파일이 생성되는 방식에 따라 이름은 각 빌드마다 고유 할 수 있습니다. (NUXT의 PWA 모듈은 파일 이름에 고유 한 UUID를 추가합니다.)
또한 기본적으로 BubbleWrap은 귀하의 웹 앱 이이 프로세스의 일부로 유효한 PWA인지 확인합니다. 어떤 이유로,이 과정을 거치고있을 때, 등대는 실제로 완전히 기능적인 프로그레시브 웹 앱임을 확인 했음에도 불구하고 수표는 계속 부정적인 것으로 돌아 왔습니다. 다행스럽게도 BubbleWrap을 사용하면이 점검을 -skippwavalidation 플래그로 건너 뛸 수 있습니다.
BubbleWrap을 처음 사용한 경우 Java Development Kit (JDK) 및 Android Software Development Kit (SDK)를 설치 해야하는지 묻습니다. 이 두 가지는 Android 앱을 생성하는 데 필요한 비하인드 유틸리티입니다. 확실하지 않으면 "Y"를 쳤다.
참고 : BubbleWrap 은이 두 가지 개발 키트가 매우 구체적인 위치 에 존재할 것으로 예상하며, 존재하지 않으면 제대로 작동하지 않습니다. BubbleWrap Doctor를 실행하여 전체 BubbleWrap CLI readme을 확인하거나 확인할 수 있습니다.
제공된 URL에서 Manifest.json 파일을 찾았다 고 가정하면 모든 것이 설치된 후 - BubbleWrap은 앱에 대해 몇 가지 질문을합니다.
많은 질문은 선호도 (앱의 기본 색상과 같은)이거나 기본 세부 사항을 확인하는 것 (앱의 도메인 및 진입 점)이며 대부분 사이트의 매니페스트 파일에서 미리 채워집니다.
매니페스트로 이미 미리 채워질 수있는 다른 질문으로는 앱의 다양한 아이콘 (홈 화면 아이콘으로 사용하기, 상태 표시 줄 아이콘 등), 앱이 열리는 동안 스플래시 화면이 어떤 색상인지, 앱의 화면 방향을 강제로 강요하려는 경우를 찾을 수있는 곳이 포함됩니다. BubbleWrap은 또한 사용자의 지리적 위치에 대한 권한을 요청할 것인지, 청구를 선택하는지 여부를 묻습니다.
그러나 약간 혼란 스러울 수있는 몇 가지 중요한 질문이 있으므로 여기에 다루겠습니다.
퍼즐의 마지막 부분은 서명 키입니다. 이것은 가장 중요한 부분입니다 . 이 키는 Progressive Web 앱을이 Android 앱에 연결하는 것입니다. 앱이 기대하는 키가 PWA에서 찾은 내용과 일치하지 않으면 다시 : 앱은 여전히 작동 하지만 사용자가 열 때 기본 앱처럼 보이지 않습니다 . 일반 브라우저 창입니다.
여기에는 자세히 설명하기에는 너무 복잡한 두 가지 접근 방식이 있지만 몇 가지 포인터를 알려 드리겠습니다.
어떤 옵션을 선택하든 앱 서명에 대한 심층적 인 설명서가 있습니다 (Android 앱 용으로 작성되었지만 대부분은 여전히 관련이 있습니다).
개인 사이트에 키를 얻는 부분은이 안내서에서 Android 앱 링크를 확인하기 위해 다루어집니다. Crudely 요약 : Google은 사이트의 정확한 경로에서 /.well-known/assetlinks.json 파일을 찾습니다. 파일에는 고유 한 키 해시와 몇 가지 다른 세부 사항이 포함되어 있어야합니다.
[{ "관계": [ "delegate_permission/common.handle_all_urls"], "대상": { "네임 스페이스": "android_app", "package_name": "your.app.id", "SHA256_CERT_FINGERPRINTS": [ "Your : Cight : HASH : HERE"]} }]
시작하기 전에 App Store 측면에서도 알아야 할 장애물도 있습니다.
While my goal with Quina was mostly personal — challenge myself, prove I could, and learn more about the Vue ecosystem in a complex real-world app — I had also hoped as a secondary goal that my work might be able to make a little money on the side for me and my family.
별로. I never had illusions of building the next Candy Crush (nor the ethical void required to engineer an addiction-fueled micro-transaction machine). But since I had poured hundreds of hours of my time and energy into the game, I had hoped that maybe I could make something in return, even if it was just a little beer money.
Initially, I didn't love the idea of trying to sell the app or lock its content, so I decided to add a simple “would you care to support Quina if you like it?” prompt after every so many games, and make some of the content unlockable specifically for supporters. (Word sets are limited in size by default, and some game settings are initially locked as well.) The prompt to support Quina can be permanently dismissed (I'm not a monster), and any donation unlocks everything; no tiered access or benefits.
This was all fairly straightforward to implement thanks to Stripe, even without a server; it's all completely client-side. I just import a bit of JavaScript on the /support page, using Nuxt's handy head function (which adds items to the
element specifically on the given page):// pages/support.vue 머리() { 반품 { script: [ { hid: 'stripe', src: 'https://js.stripe.com/v3', defer: true, callback: () => { // Adds all Stripe methods like redirectToCheckout to page component this.stripe = Stripe('your_stripe_id') }, }, ],, } },
With that bit in place (along with a sprinkle of templating and logic), users can choose their donation amount — set up as products on the Stripe side — and be redirected to Stripe to complete payment, then returned when finished. For each tier, the return redirect URL is slightly different via query parameters. Vue Router parses the URL to adjust the user's stored donation history, and unlock features accordingly.
You might wonder why I'm revealing all of this, since it exposes the system as fairly easy to reverse-engineer. The answer is: I don't care . In fact, I added a free tier myself, so you don't even have to go to the trouble. I decided that if somebody really wanted the unlockables but couldn't or wouldn't pay for whatever reason, that's fine. Maybe they live in a situation where $3 is a lot of money. Maybe they gave on one device already. Maybe they'll do something else nice instead. But honestly, even if their intentions aren't good: so what?
I appreciate support, but this isn't my living, and I'm not trying to build a dopamine tollbooth. Besides, I'm not personally comfortable with the ethical implications of using a stack of totally open-source and/or free software (not to mention the accompanying mountain of documentation, blog posts, and Stack Overflow answers written about all of it) to build a closed garden for personal profit.
So, if you like Quina and can support it: sincerely, thank you . That means a ton to me. I love to see my work being enjoyed. But if not: that's cool. If you want the “free” option, it's there for you.
Anyway, this whole plan hit a snag when I learned about Google Play's new monetization policy, effective this year. You can read it yourself, but to summarize: if you make money through a Google Play app and you're not a nonprofit, you gotta go through Google Pay and pay a hefty fee — you are not allowed to use any other payment provider.
This meant I couldn't even list the app; it would be blocked just for having a “support” page with payments that don't go through Google. (I suppose I probably could have gotten around this by registering a nonprofit, but that seemed like the wrong way to go about it, on a number of levels.)
My eventual solution was to charge for the app itself on Google Play, by listing it for $2.99 (rather than my previously planned price of “free”), and simply altering the app experience for Android users accordingly.
Fortunately enough, Android apps send a custom header with the app's unique ID when requesting a website. Using this header, it was easy enough to differentiate the app's experience on the web and in the actual Android app.
For each request, the app checks for the Android ID; if present, the app sets a Vuex state boolean called isAndroid to true. This state cascades throughout the app, working to trigger various conditionals to do things like hide and show various FAQ questions, and (most importantly) to hide the support page in the nav menu. It also unlocks all content by default (since the user's already “donated” on Android, by purchasing). I even went so far as to make simple
<!-- /src/components/AndroidOnly.vue --> <emplate> <div v-if="isAndroid"> <slot></slot> </div> 템플릿> <cript> 내보내기 기본값 { computed: { isAndroid() { return this.$store.state.isAndroid }, }, } 스크립트></cript></emplate>
For a time while building Quina, I had Firebase set up for logins and storing user data. I really liked the idea of allowing users to play on all their devices and track their stats everywhere, rather than have a separate history on each device/browser.
In the end, however, I scrapped that idea, for a few reasons. One was complexity; it's not easy maintaining a secure accounts system and database, even with a nice system like Firebase, and that kind of overhead isn't something I took lightly. But mainly: the decision boiled down to security and simplicity.
At the end of the day, I didn't want to be responsible for users' data. Their privacy and security is guaranteed by using localStorage, at the small cost of portability. I hope players don't mind the possibility of losing their stats from time to time if it means they have no login or data to worry about. (And hey, it also gives them a chance to earn those awards all over again.)
Plus, it just feels nice. I get to honestly say there's no way my app can possibly compromise your security or data because it knows literally nothing about you. And also, I don't need to worry about compliance or cookie warnings or anything like that, either.
Building Quina was my most ambitious project to date, and I had as much fun designing and engineering it as I have seeing players enjoy it.
I hope this journey has been helpful for you! While getting a web app listed in the Google Play Store has a lot of steps and potential pitfalls, it's definitely within reach for a front-end developer. I hope you take this story as inspiration, and if you do, I'm excited to see what you build with your newfound knowledge.
위 내용은 Google Play에서 Nuxt와 함께 단어 게임 앱 구축을 배운 것의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!