React-native: [Android] ์˜ค๋ฅ˜ : ์ค‘๋ณต ๋ฆฌ์†Œ์Šค

์— ๋งŒ๋“  2018๋…„ 11์›” 10์ผ  ยท  103์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: facebook/react-native

ํ™˜๊ฒฝ

React Native ํ™˜๊ฒฝ ์ •๋ณด :

System:
  OS: macOS 10.14
  CPU: (4) x64 Intel(R) Core(TM) i5-7267U CPU @ 3.10GHz
  Memory: 103.10 MB / 8.00 GB
  Shell: 3.2.57 - /bin/bash
Binaries:
  Node: 8.12.0 - /usr/local/bin/node
  Yarn: 1.0.1 - /usr/local/bin/yarn
  npm: 6.4.1 - /usr/local/bin/npm
  Watchman: 4.7.0 - /usr/local/bin/watchman
SDKs:
  iOS SDK:
    Platforms: iOS 12.1, macOS 10.14, tvOS 12.1, watchOS 5.1
  Android SDK:
    API Levels: 16, 17, 19, 21, 23, 24, 25, 26, 27, 28
    Build Tools: 19.1.0, 20.0.0, 23.0.1, 23.0.2, 23.0.3, 25.0.0, 25.0.1, 25.0.2, 25.0.3, 26.0.0, 26.0.1, 26.0.2, 26.0.3, 27.0.0, 27.0.1, 27.0.3, 28.0.0, 28.0.0, 28.0.2, 28.0.3
    System Images: android-16 | ARM EABI v7a, android-16 | MIPS, android-16 | Intel x86 Atom, android-16 | Google APIs Intel x86 Atom, android-19 | Google APIs Intel x86 Atom, android-24 | Google Play Intel x86 Atom, android-26 | Google APIs Intel x86 Atom, android-26 | Google APIs Intel x86 Atom_64, android-26 | Google Play Intel x86 Atom, android-27 | Google Play Intel x86 Atom, android-28 | Google APIs Intel x86 Atom, android-P | Google APIs Intel x86 Atom, android-P | Google Play Intel x86 Atom
IDEs:
  Android Studio: 3.2 AI-181.5540.7.32.5056338
  Xcode: 10.1/10B61 - /usr/bin/xcodebuild
npmPackages:
  react: 16.6.0-alpha.8af6728 => 16.6.0-alpha.8af6728 
  react-native: 0.57.4 => 0.57.4 
npmGlobalPackages:
  babel-preset-react-native: 4.0.0
  react-native-cli: 2.0.1
  react-native-create-library: 3.1.2
  react-native-git-upgrade: 0.2.7

๊ธฐ์ˆ 

Android์—์„œ PNG ์ด๋ฏธ์ง€๋กœ ๋ฆด๋ฆฌ์Šค APK๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ PNG ์ด๋ฏธ์ง€๊ฐ€์—†๋Š” ๊ฒฝ์šฐ ๋ฆด๋ฆฌ์Šค APK๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฆด๋ฆฌ์Šค ๋นŒ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋™์•ˆ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

[drawable-mdpi-v4/assets_mario] /Users/jeffreyrajan/Tutorials/RN/errorCheck/android/app/src/main/res/drawable-mdpi/assets_mario.png [drawable-mdpi-v4/assets_mario] /Users/jeffreyrajan/Tutorials/RN/errorCheck/android/app/build/generated/res/react/release/drawable-mdpi-v4/assets_mario.png: Error: Duplicate resources
:app:mergeReleaseResources FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:mergeReleaseResources'.
> [drawable-mdpi-v4/assets_mario] /Users/jeffreyrajan/Tutorials/RN/errorCheck/android/app/src/main/res/drawable-mdpi/assets_mario.png   [drawable-mdpi-v4/assets_mario] /Users/jeffreyrajan/Tutorials/RN/errorCheck/android/app/build/generated/res/react/release/drawable-mdpi-v4/assets_mario.png: Error: Duplicate resources

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ๋ฐ๋ชจ

  1. ์•ฑ ๋งŒ๋“ค๊ธฐ- react-native init demo
  2. ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ ํด๋”์— assets ํด๋”๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
  3. asset ํด๋” ์•ˆ์— PNG ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค.
  4. ์ด์ œ ์œ„์˜ PNG ์ด๋ฏธ์ง€๋กœ image ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  5. ์ด์ œ cmd๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฒˆ๋“ค๋กœ ๋ฌถ์œผ์‹ญ์‹œ์˜ค.
    react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/
  6. ๊ทธ๋Ÿฐ ๋‹ค์Œ Generate Signed APK ์‚ฌ์šฉํ•˜์—ฌ ๋ฆด๋ฆฌ์Šค APK๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
Bug Android

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

Mapsy์˜ ๋‹ต๋ณ€์€ https://stackoverflow.com/a/52750886์— ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ /node_modules/react-native/react.gradle ํŒŒ์ผ์„ ํŽธ์ง‘ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ์ˆ˜๋™์œผ๋กœ doFirst ๋ธ”๋ก ํ›„ doLast์˜ ๊ถŒ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

doFirst { ... }
doLast {
    def moveFunc = { resSuffix ->
        File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
            ant.move(file: originalDir, tofile: destDir);
        }
    }
    moveFunc.curry("ldpi").call()
    moveFunc.curry("mdpi").call()
    moveFunc.curry("hdpi").call()
    moveFunc.curry("xhdpi").call()
    moveFunc.curry("xxhdpi").call()
    moveFunc.curry("xxxhdpi").call()
}

๋ชจ๋“  103 ๋Œ“๊ธ€

https://github.com/facebook/react-native/issues/19239#issuecomment -414564404๋ฅผ ํ™•์ธ

๋“œ๋กœ์–ด ๋ธ” ํด๋” ์ด๋ฏธ์ง€๊ฐ€์žˆ๋Š” ๊ฒฝ์šฐ ์ œ๊ฑฐํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ?

@ ZeroCool00 ์€ Android์˜ ์ด๋ฏธ์ง€์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ?

Mapsy์˜ ๋‹ต๋ณ€์€ https://stackoverflow.com/a/52750886์— ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ /node_modules/react-native/react.gradle ํŒŒ์ผ์„ ํŽธ์ง‘ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ์ˆ˜๋™์œผ๋กœ doFirst ๋ธ”๋ก ํ›„ doLast์˜ ๊ถŒ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

doFirst { ... }
doLast {
    def moveFunc = { resSuffix ->
        File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
            ant.move(file: originalDir, tofile: destDir);
        }
    }
    moveFunc.curry("ldpi").call()
    moveFunc.curry("mdpi").call()
    moveFunc.curry("hdpi").call()
    moveFunc.curry("xhdpi").call()
    moveFunc.curry("xxhdpi").call()
    moveFunc.curry("xxxhdpi").call()
}

@ ZeroCool00 @mkchx ๋‘ ๊ฐ€์ง€ ๋‹ต๋ณ€์„ ๋ชจ๋‘ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค :)

์•ˆ๋…•ํ•˜์‹ญ๋‹ˆ๊นŒ, ์  ํ‚จ์Šค ์ž‘์—…์œผ๋กœ ์–ด๋–ป๊ฒŒ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? npm ์„ค์น˜๋ฅผ ํ•ญ์ƒ ์ˆ˜ํ–‰ํ•˜๋ฏ€๋กœ react.gradle ํŒŒ์ผ์˜์ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ฌด์‹œํ•ฉ๋‹ˆ๋‹ค. ์•ˆ๋“œ๋กœ์ด๋“œ ์šฉ ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค์—์„œ ๋นŒ๋“œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ ์  ํ‚จ์Šค์—์„œ๋Š” ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” @ vivek-walecha-657 ๋‚˜๋Š” ์ด๊ฒƒ์„ ์‹œ๋„ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ์˜คํ”„๋ผ์ธ ๋ฒˆ๋“ค๋ง์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์ด ๋ช…๋ น์„ ์‹œ๋„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle

@jeffreyrajanofficial ์ž‘์„ฑ์„ ์œ„ํ•ด Thanx, ๋‹น์‹ ์ด ์ œ๊ณต ํ•œ ์†”๋ฃจ์…˜์€ ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์„œ react.gradle ํŒŒ์ผ์„ ๋ณ€๊ฒฝํ•˜๋ฉด ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ npm์„ ์–ด๋””์—๋‚˜ ์„ค์น˜ํ•  ๋•Œ๋งˆ๋‹ค react.gradle ํŒŒ์ผ์„ ๋ณ€๊ฒฝํ•˜์—ฌ ๋ฆด๋ฆฌ์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@jeffreyrajanofficial ์ด ๋ฌธ์ œ์—†์ด ์–ด๋–ค ๋ฒ„์ „ (์ด๋ณด๋‹ค ๋‚ฎ๊ฑฐ๋‚˜ ์ด๋ณด๋‹ค ๋†’์€ ์ตœ์‹  ๋ฒ„์ „)์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ์•Œ๋ ค์ฃผ์„ธ์š”. ๋ฆด๋ฆฌ์Šค ์ •๋ณด๋Š”์ด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Œ์„ ์•Œ๋ฆฌ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์ด์ œ RN> 57์—์„œ ์ •๋ ฌ๋ฉ๋‹ˆ๋‹ค. react.gradle ํŒŒ์ผ์€ ์ž๋™์œผ๋กœ ๋ฒˆ๋“ค์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
๋ฆด๋ฆฌ์Šค ๋นŒ๋“œ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด npm run build : android : release ๋ฅผ ์‹คํ–‰ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค

์—ฌ๊ธฐ์— 55.4 ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ˆ˜์ • ์‚ฌํ•ญ์ด์žˆ๋Š” build.gradle package.json์— ๋Œ€ํ•œ ์ƒ˜ํ”Œ ํ”„๋กœ์ ํŠธ ์š”์ ์ž…๋‹ˆ๋‹ค.

https://gist.github.com/Abhishekgarg727/daf031fb9f94fdfd985e84db57dedbe1

macOS 10.14.3 + RN 0.57.8 + Android Studio 3.3 + Gradle 4.10.3์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ์ „ํžˆ ์ด๊ฒƒ์„๋ณด๊ณ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์œ ์ผํ•œ ์‚ฌ๋žŒ์ด ์•„๋‹๊นŒ์š”? ์•„๋‹ˆ๋ฉด ์—ฌ๊ธฐ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋” ๋งŽ์ด ํŒŒ๊ณ  ์‹ค์ œ๋กœ ์ˆ˜์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ €๋Š” ํ˜„์žฌ @mkchx ( .txt ์ ‘๋ฏธ์‚ฌ๊ฐ€ ์ถ”๊ฐ€๋˜์–ด github์—์„œ ์ฒจ๋ถ€ ํŒŒ์ผ์„ ํ—ˆ์šฉ ํ•จ) ์˜ ์œ„ ์ฃผ์„ ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฒจ๋ถ€ ๋œ ํŒจ์น˜์™€ ํ•จ๊ป˜ "patch-package"ํŒจํ‚ค์ง€ ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋™์œผ๋กœ ์ž‘์—…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด package.json ์Šคํฌ๋ฆฝํŠธ์— postinstall: patch-package ์„ ์ถ”๊ฐ€ ํ•œ ํ›„ 'npm install'์—์„œ ์ˆ˜์ •ํ•˜์‹ญ์‹œ์˜ค.

๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ์œ ์šฉ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค ...
react-native + 0.57.8.patch.txt

๊ฐ€์ง€๊ณ ์žˆ์„ ์ˆ˜์žˆ๋Š” ํŒŒ์ผ์„ ์ œ๊ฑฐํ•˜์‹ญ์‹œ์˜ค.

์•ˆ๋“œ๋กœ์ด๋“œ / ์•ฑ / src / main / res / drawable-mdpi /
์•ˆ๋“œ๋กœ์ด๋“œ / ์•ฑ / src / main / res / drawable-xhdpi /
์•ˆ๋“œ๋กœ์ด๋“œ / ์•ฑ / src / main / res / drawable-xxhdpi /
๋นŒ๋“œ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์—ฌ์ „ํžˆ RN0.58.x์—์„œ ์ด๊ฒƒ์„ ๋ณด์•˜๊ณ  RN0.59.x์—์„œ ๊ณ„์†๋ฉ๋‹ˆ๋‹ค-์šฐ๋ฆฌ๊ฐ€ ์—ฌ๊ธฐ์„œ ๋ญ”๊ฐ€ ์ž˜๋ชปํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ ์•„๋‹ˆ๋ฉด ์ด๊ฒƒ์ด ์ •๋ง๋กœ ๋ฒ„๊ทธ์ž…๋‹ˆ๊นŒ?

ํŒจ์น˜ ํŒจํ‚ค์ง€ ๋ชจ๋“ˆ ๋ฐ์ด ํŒจ์น˜ (RN0.59.1 ์šฉ์œผ๋กœ ์—…๋ฐ์ดํŠธ ๋จ)์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํŒจ์น˜ ๋””๋ ‰ํ† ๋ฆฌ์— ํŒจ์น˜ ํ˜•์‹์œผ๋กœ ์ธ์ฝ”๋”ฉ ๋œ @mkchx ์˜ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ณ„์† ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.

react-native + 0.59.1.patch.txt

์‚ฌ์šฉ์ž ์ง€์ • ํด๋”์— ์ถ”๊ฐ€ ๋ฆฌ์†Œ์Šค๊ฐ€์žˆ๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‹œ๋„ํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

doLast {
    def moveFunc = { resSuffix ->
        File originalDir = file("$buildDir/generated/res/react/release/${resSuffix}");
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/${resSuffix}");
            ant.move(file: originalDir, tofile: destDir);
        }
    }
    moveFunc.curry("drawable-ldpi").call()
    moveFunc.curry("drawable-mdpi").call()
    moveFunc.curry("drawable-hdpi").call()
    moveFunc.curry("drawable-xhdpi").call()
    moveFunc.curry("drawable-xxhdpi").call()
    moveFunc.curry("drawable-xxxhdpi").call()
    moveFunc.curry("raw").call()
}

๊ทธ๋Ÿฌ๋‚˜ ์ž์ฒด ์ž์‚ฐ์„ ํŒจํ‚นํ•˜๋Š” ์ข…์†์„ฑ์ด์žˆ๋Š” ๊ฒฝ์šฐ ์ž‘๋™ํ•˜์ง€ ์•Š๊ณ  ์—ฌ์ „ํžˆ ๋‹ค์Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค (๋ช…ํ™•์„ฑ์„ ์œ„ํ•ด ํŽธ์ง‘ ๋จ).

Execution failed for task ':app:mergeReleaseResources'.

> [drawable-xxxhdpi-v4/node_modules_reactnavigationstack_dist_views_assets_backicon] 
/[...]/android/app/src/main/res/drawable-xxxhdpi/node_modules_reactnavigationstack_dist_views_assets_backicon.png

[drawable-xxxhdpi-v4/node_modules_reactnavigationstack_dist_views_assets_backicon] 
/[...]/android/app/build/generated/res/react/release/drawable-xxxhdpi/node_modules_reactnavigationstack_dist_views_assets_backicon.png: 

Error: Duplicate resources

์ด๊ฒƒ์€ ์ ๊ทน์ ์œผ๋กœ ํ‰๊ฐ€๋˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ์ž์ฒด ํŒจ์น˜๋ฅผ ์ง„ํ–‰ํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ?

@dragosroua xxxhdpi ์นด๋ ˆ์— ๋ˆ„๋ฝ ๋œ ํ•˜์ดํ”ˆ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ์—ฐํžˆ ๋ฌธ์ œ๊ฐ€์žˆ๋Š” ๋™์ผํ•œ ์„ ๋„ ๊ฒฝ๋กœ์ž…๋‹ˆ๊นŒ?

๋‹น์‹ ์€ ๋‚˜๋ฅผ 2 ๋ถ„์œผ๋กœ ์ด๊ฒผ๊ณ , ๋‚˜๋Š” ๊ทธ ๋ถ€๋ถ„์„ ํŽธ์ง‘ํ•˜๋ ค๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ, ์ด์ œ ๋ชจ๋“  ๊ฒƒ์ด ๋ฒˆ๋“ค๋กœ ์ œ๊ณต๋˜์ง€๋งŒ ์‚ฌ์šฉ์ž ์ง€์ • ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ "์›์‹œ"๊ฒฝ๋กœ๊ฐ€์žˆ๋Š” ๋น„ํŠธ๋Š” ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ์œ ์šฉ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@dragosroua ๋‹น์‹ ์ด ์ง€๊ธˆ ์ปดํŒŒ์ผํ•˜๊ณ 

macOS 10.14.3 + RN 0.57.8 + Android Studio 3.3 + Gradle 4.10.3์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ์ „ํžˆ ์ด๊ฒƒ์„๋ณด๊ณ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์œ ์ผํ•œ ์‚ฌ๋žŒ์ด ์•„๋‹๊นŒ์š”? ์•„๋‹ˆ๋ฉด ์—ฌ๊ธฐ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋” ๋งŽ์ด ํŒŒ๊ณ  ์‹ค์ œ๋กœ ์ˆ˜์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ €๋Š” ํ˜„์žฌ @mkchx ( .txt ์ ‘๋ฏธ์‚ฌ๊ฐ€ ์ถ”๊ฐ€๋˜์–ด github์—์„œ ์ฒจ๋ถ€ ํŒŒ์ผ์„ ํ—ˆ์šฉ ํ•จ) ์˜ ์œ„ ์ฃผ์„ ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฒจ๋ถ€ ๋œ ํŒจ์น˜์™€ ํ•จ๊ป˜ "patch-package"ํŒจํ‚ค์ง€ ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋™์œผ๋กœ ์ž‘์—…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด package.json ์Šคํฌ๋ฆฝํŠธ์— postinstall: patch-package ์„ ์ถ”๊ฐ€ ํ•œ ํ›„ 'npm install'์—์„œ ์ˆ˜์ •ํ•˜์‹ญ์‹œ์˜ค.

๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ์œ ์šฉ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค ...
react-native + 0.57.8.patch.txt

Pls๋Š” ๋‚ด ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ 0.57.5์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
pacth ํŒŒ์ผ์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. package.json์— ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. npm install์„ ์‹คํ–‰ํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ

        def currentBundleTask = tasks.create(
            name: "bundle${targetName}JsAndAssets",
            type: Exec) {
            group = "react"
            description = "bundle JS and assets for ${targetName}."

            // Create dirs if they are not there (e.g. the "clean" task just ran)
            doFirst {
                jsBundleDir.deleteDir()
                jsBundleDir.mkdirs()
                resourcesDir.deleteDir()
                resourcesDir.mkdirs()
            }

            // Set up inputs and outputs so gradle can cache the result
            inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
            outputs.dir jsBundleDir
            outputs.dir resourcesDir

ํ•„์š”ํ•œ ๋ณ€๊ฒฝ์—†์ด.

@zakabluk ๋Š” npm ์„ค์น˜์˜ ์ถœ๋ ฅ์„ ๊ฒŒ์‹œํ•ด์•ผํ•˜์ง€๋งŒ, ์ถ”์ธก์œผ๋กœ๋Š” ํŒจ์น˜ ํŒจํ‚ค์ง€ ํŒจํ‚ค์ง€๊ฐ€ ๋ฒ„์ „ ๋ฒˆํ˜ธ์— ๋Œ€ํ•ด ๋งค์šฐ ์‹ ์ค‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. 57.5์—์„œ ์‹œ๋„ํ•˜๊ณ  ์žˆ์ง€๋งŒ ํŒจ์น˜๋Š” 57.8์— ๋Œ€ํ•œ ๊ฒƒ์ž…๋‹ˆ๊นŒ?

์ €๋Š” ๋ณดํ†ต node_modules ํŒจ์น˜๋ฅผ์œ„ํ•œ ํŒŒ์ด์ฌ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
์ด๊ฒƒ์„ postinstall.py ๋กœ ์ถ”๊ฐ€ํ•˜๊ณ  ์„ค์น˜ ํ›„ ์Šคํฌ๋ฆฝํŠธ์— ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ./postinstall.py

#!/usr/bin/env python3

import os
import textwrap

def file_dir():
  return os.path.dirname(os.path.realpath(__file__))

def read_file(filename):
    '''
    Reads the specified file.

    :param filename: The file to read
    :return: The content of the specified file
    '''
    if os.path.exists(filename):
        with open(filename, "r") as file:
            return file.read()
    else:
        raise IOError("file {} not found.".format(filename))

def write_file(filename, text):
    '''
    Writes the specified text to the specified file.

    :param filename: The file to write to
    :param text: The text to write
    '''
    with open(filename, "w") as file:
        file.write(text)

def fix_android_assets():
  print("Fixing android error with duplicate assets: https://github.com/facebook/react-native/issues/22234")

  gradle_file_path = "{}/node_modules/react-native/react.gradle".format(file_dir())

  code_snippet = textwrap.indent("""\
            // Added by post_install
            // Fix for: https://github.com/facebook/react-native/issues/22234
            doLast {
                def moveFunc = { resSuffix ->
                    File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");
                    if (originalDir.exists()) {
                        File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
                        ant.move(file: originalDir, tofile: destDir);
                    }
                }
                moveFunc.curry("ldpi").call()
                moveFunc.curry("mdpi").call()
                moveFunc.curry("hdpi").call()
                moveFunc.curry("xhdpi").call()
                moveFunc.curry("xxhdpi").call()
                moveFunc.curry("xxxhdpi").call()
            }
  """, "")

  text = read_file(gradle_file_path)

  start = text.find("doFirst", 0)
  end = text.find("}", start)
  end = text.find("\n", end) + 1

  text = text[:end] + code_snippet + text[end:]

  write_file(gradle_file_path, text)

def main():
    fix_android_assets()

if __name__ == "__main__":
    main()

ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์—ฌ๊ธฐ์—์„œ ์ž์‹ ์˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

npm install patch-package ์–ป์€ ๊ฒƒ์„ ๋‹ค์‹œ ๊ตฌํ˜„ ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ํŒŒ์ด์ฌ์ด ๋‹น์‹ ์˜ ๊ฒƒ์ด๊ณ  ๋” ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์œ ์ง€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์‹คํ–‰ ๊ฐ€๋Šฅํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ์—ฌ์ „ํžˆ 0.59.3๊ณผ ๊ฐ™์ด ๊ฐ€์น˜์žˆ๋Š” ํŒจ์น˜ ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
react-native + 0.59.3.patch.txt

@hramos- # 19239๋Š” ๋น„์Šทํ–ˆ๊ณ  (๋‚ด ์ƒ๊ฐ์—) ์ด๊ฒƒ์€ ์˜ค๋ž˜๋˜์—ˆ์ง€๋งŒ ์ˆ˜์ • ๋œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. ๊ถ๊ทน์  ์ธ ์ˆ˜์ •์„ ์œ„ํ•ด PR์ด ํ•„์š”ํ•ฉ๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ์—ฌ๊ธฐ์— ์‚ฌ์šฉ ๋œ ํŒจ์น˜๊ฐ€ ์‹คํ–‰ ๋ถˆ๊ฐ€๋Šฅํ•œ ์ด์œ ๋ฅผ ๋†“์น˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? (์•„๋งˆ๋„). PR ๋งŒ ํ•„์š”ํ•˜๋ฉด ๋ณด๋‚ด๋“œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ...

npm install patch-package ์–ป์€ ๊ฒƒ์„ ๋‹ค์‹œ ๊ตฌํ˜„ ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ํŒŒ์ด์ฌ์ด ๋‹น์‹ ์˜ ๊ฒƒ์ด๊ณ  ๋” ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์œ ์ง€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์‹คํ–‰ ๊ฐ€๋Šฅํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ์—ฌ์ „ํžˆ 0.59.3๊ณผ ๊ฐ™์ด ๊ฐ€์น˜์žˆ๋Š” ํŒจ์น˜ ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
react-native + 0.59.3.patch.txt

@hramos- # 19239๋Š” ๋น„์Šทํ–ˆ๊ณ  (๋‚ด ์ƒ๊ฐ์—) ์ด๊ฒƒ์€ ์˜ค๋ž˜๋˜์—ˆ์ง€๋งŒ ์ˆ˜์ • ๋œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. ๊ถ๊ทน์  ์ธ ์ˆ˜์ •์„ ์œ„ํ•ด PR์ด ํ•„์š”ํ•ฉ๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ์—ฌ๊ธฐ์— ์‚ฌ์šฉ ๋œ ํŒจ์น˜๊ฐ€ ์‹คํ–‰ ๋ถˆ๊ฐ€๋Šฅํ•œ ์ด์œ ๋ฅผ ๋†“์น˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? (์•„๋งˆ๋„). PR ๋งŒ ํ•„์š”ํ•˜๋ฉด ๋ณด๋‚ด๋“œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ...

์ด ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•, ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

@ZhanRu - https: //github.com/ds300/patch-package#set -up- ํŒจ์น˜๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์„ค์ • ํ•œ ํ›„ ํ•ด๋‹น ํŒจ์น˜ (.patch ํ™•์žฅ์ž ํฌํ•จ)๋ฅผ ํ”„๋กœ์ ํŠธ์˜ 'patches'๋””๋ ‰ํ† ๋ฆฌ์— ๋„ฃ์œผ๋ฉด๋ฉ๋‹ˆ๋‹ค. ๊พธ๋Ÿฌ๋ฏธ

@ZhanRu - https: //github.com/ds300/patch-package#set -up- ํŒจ์น˜๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์„ค์ • ํ•œ ํ›„ ํ•ด๋‹น ํŒจ์น˜ (.patch ํ™•์žฅ์ž ํฌํ•จ)๋ฅผ ํ”„๋กœ์ ํŠธ์˜ 'patches'๋””๋ ‰ํ† ๋ฆฌ์— ๋„ฃ์œผ๋ฉด๋ฉ๋‹ˆ๋‹ค. ๊พธ๋Ÿฌ๋ฏธ

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

๊ณ„์† ๋”ฐ๋ผ๊ฐ€๋Š” ์‚ฌ๋žŒ์„ ์œ„ํ•ด ์ตœ๊ทผ์— ์™ธ๋ถ€ ์‹œ์Šคํ…œ์„ ํ†ตํ•ฉํ•˜๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ํ”„๋กœ๋•์…˜ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ์™€ ๋ถ„๋ฆฌํ•ด์•ผํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— gradle์—์„œ "flavors"๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ qaDebug, stagingRelease ๋“ฑ์ด ๋‹ค๋ฅธ ์™ธ๋ถ€ ์‹œ์Šคํ…œ์„ ๊ฐ€๋ฆฌ ํ‚ค๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์˜ ํŒจ์น˜๋Š” ๊ทธ๊ฒƒ์„ ์ง€์›ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‚˜๋Š” ํ”Œ๋ ˆ์ด๋ฒ„ ์ง€์›์„ ์ถ”๊ฐ€ํ–ˆ๊ณ , ๋‚ด ํŒจ์น˜๋Š” ์ง€๊ธˆ ์ด๋ ‡๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค. patches/react-native+0.59.5.patch ๊ฑฐ์ฃผํ•˜๋ฉฐ npm install patch-package ํ›„ npm i ์‹คํ–‰ ์ค‘์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

diff --git a/node_modules/react-native/react.gradle b/node_modules/react-native/react.gradle
index 4ead2b6..e0f92b7 100644
--- a/node_modules/react-native/react.gradle
+++ b/node_modules/react-native/react.gradle
@@ -48,6 +48,33 @@ afterEvaluate {
                 resourcesDir.mkdirs()
             }

+            // From https://stackoverflow.com/questions/53239705/react-native-error-duplicate-resources-android
+            // Currently has no solution?
+
+            // IF you are using flavors, add flavor name to the path you move from
+            def flavorPathSegment = ""
+            android.productFlavors.all { flavor ->
+                if (targetName.toLowerCase().contains(flavor.name)) {
+                    flavorPathSegment = flavor.name + "/"
+                }
+            }
+
+            doLast {
+                def moveFunc = { resSuffix ->
+                    File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/drawable-${resSuffix}")
+                    if (originalDir.exists()) {
+                        File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}")
+                        ant.move(file: originalDir, tofile: destDir);
+                    }
+                }
+                moveFunc.curry("ldpi").call()
+                moveFunc.curry("mdpi").call()
+                moveFunc.curry("hdpi").call()
+                moveFunc.curry("xhdpi").call()
+                moveFunc.curry("xxhdpi").call()
+                moveFunc.curry("xxxhdpi").call()
+            }
+
             // Set up inputs and outputs so gradle can cache the result
             inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
             outputs.dir(jsBundleDir)

์ œ ๊ฒฝ์šฐ์—๋Š” raw ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ๋ฌธ์ œ๊ฐ€ ์ง€์†๋ฉ๋‹ˆ๋‹ค.

๋ฒ„์ „ : react-native 0.59.5

๋‚ด ์†”๋ฃจ์…˜ :

doLast {                                                                                            
  def moveFunc = { resSuffix ->                                                                   
    File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");     
    if (originalDir.exists()) {                                                                 
      File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");                 
      ant.move(file: originalDir, tofile: destDir);                                           
    }
  } 
  def moveRawFunc = { dir ->                                                                   
    File originalDir = file("$buildDir/generated/res/react/release/${dir}");     
    if (originalDir.exists()) {                                                                 
      File destDir = file("$buildDir/../src/main/res/${dir}");                 
      ant.move(file: originalDir, tofile: destDir);                                           
    }
  }  
  moveFunc.curry("ldpi").call()
  moveFunc.curry("mdpi").call()
  moveFunc.curry("hdpi").call()
  moveFunc.curry("xhdpi").call()
  moveFunc.curry("xxhdpi").call()
  moveFunc.curry("xxxhdpi").call()
  moveRawFunc.curry("raw").call()
}

๋ฌธ์•ˆ ์ธ์‚ฌ

@Dbroqua ๊ท€ํ•˜์˜ ์†”๋ฃจ์…˜์ด ์ €์—๊ฒŒ react-native 0.59.5 ). ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋งค์šฐ ํฅ๋ฏธ ๋กญ์Šต๋‹ˆ๋‹ค. ์ €๋Š” raw์— ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ์ตœ์‹  ๋ฒ„์ „์˜ ํŒจ์น˜์— ํ”Œ๋ ˆ์ด๋ฒ„์— ๋Œ€ํ•œ ์ง€์›์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ”Œ๋ ˆ์ด๋ฒ„๋ฅผ ์‹œ์ž‘ํ•˜๋ฉด ๋‘ ๊ธฐ๋Šฅ ๋ชจ๋‘์—์„œ ํ”Œ๋ ˆ์ด๋ฒ„ ์ง€์›์„ ์›ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์–ด์ฉŒ๋ฉด ๊ทธ๊ฒƒ์€ ๋งค๊ฐœ ๋ณ€์ˆ˜ํ™” ๋  ์ˆ˜์žˆ์–ด์„œ 2 ๊ฐœ์˜ ๊ธฐ๋Šฅ์ด ๋ฐ˜๋ณต์ ์ด์ง€๋Š” ์•Š์ง€๋งŒ ๊ทธ๊ฒƒ์„ ๊ณ ๋ คํ• ๋งŒํผ ๊ทธ๋ฃจ๋น„๋ฅผ ์ž˜ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด ํŽ˜์ด์Šค ๋ถ๊ณผ ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ CI์—์„œ ๋ฌธ์ œ๊ฐ€๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๊ทธ๋“ค์ด BUCK๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ณ  ๊ทธ๋“ค์˜ CI๋Š” ๋งค๋ฒˆ ๊นจ๋—ํ•˜๊ฒŒ ๋นŒ๋“œ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ˆ„๊ตฌ๋“ ์ง€ ์ด๊ฒƒ์„ ๊นจ๋—ํ•˜๊ฒŒ ์žฌํ˜„ํ•˜์—ฌ ์—…์ŠคํŠธ๋ฆผ์—์„œ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ œ ๊ฒฝ์šฐ์—๋Š” ์›์‹œ ๋””๋ ‰ํ† ๋ฆฌ์— ๋‚ด ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ผ๋ถ€ mp3๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ๋น ๋ฅด๊ณ  ์‰ฌ์šด ์žฌํ˜„์˜ ๊ธฐ์ดˆ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” (์•„์ง) ๊ทธ๋Ÿฐ ์• ์…‹์ด ์—†์ง€๋งŒ repo์— ๋Œ€ํ•œ ๋„ค์ดํ‹ฐ๋ธŒ ์ดˆ๊ธฐํ™”์— ๋ฐ˜์‘ ํ•  ์ˆ˜์žˆ์„๋งŒํผ ์‰ฝ์Šต๋‹ˆ๋‹ค. ์• ์…‹์„ ๋ช‡ ๊ฐœ ๋„ฃ์€ ๋‹ค์Œ ๋‘ ๋ฒˆ์งธ ๋ฆด๋ฆฌ์Šค ๋นŒ๋“œ (์•„๋งˆ๋„ ์ฒซ ๋ฒˆ์งธ ๋นŒ๋“œ์ผ๊นŒ์š”?)์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@Dbroqua ๋Š”์ฃผ์˜ ํ•  ์ ์ž…๋‹ˆ๋‹ค. ์ œ ํŒจ์น˜๋Š” ๋ณ‘ํ•ฉ๋˜์—ˆ์ง€๋งŒ ์›์‹œ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ๋งค์šฐ ๋ฐ€์ ‘ํ•˜๊ฒŒ ๊ด€๋ จ๋˜์–ด ์žˆ์ง€๋งŒ ์ œ ํŒจ์น˜์— ํฌํ•จ๋˜์ง€ ์•Š์•˜๋‹ค๋Š” ์–ธ๊ธ‰๋„ ๋ณ‘ํ•ฉ์— ๋ฐ˜์˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ํŒจ์น˜๊ฐ€ ์ ์šฉ๋˜์—ˆ์œผ๋ฏ€๋กœ ์›์‹œ ๋””๋ ‰ํ† ๋ฆฌ์— ํ•„์š”ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํ™•์ธํ•˜๊ณ  ์ˆ˜์ • ์‚ฌํ•ญ์„ ๊ณ„์†ํ•˜์—ฌ PR์„ ์ œ์•ˆํ•˜์—ฌ ์‚ฌ๋ก€๋ฅผ ํ™•์žฅ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

ํ™•์ธ,

๋‚˜๋Š” ํ•„์š”ํ•œ ์ตœ๋Œ€ํ•œ ๋นจ๋ฆฌ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฌธ์•ˆ ์ธ์‚ฌ,
๋ฐ๋ฏธ์•ˆ

๊ฒฐ์ •๋œ!

์ œ ๊ฒฝ์šฐ์—๋Š” ๋“œ๋กœ์–ด ๋ธ” res/drawable-* ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋‚ด ํŒ€ ์ปค๋ฐ‹์˜ ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž์—์„œ ๋‚จ์•„์žˆ๋Š” ํŒŒ์ผ์ด์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.-ํ•ด๋‹น ํŒŒ์ผ ์ด๋ฆ„์„ ๊ฐ€๋ฆฌํ‚ค๋Š” "์˜ค๋ฅ˜ : ์ค‘๋ณต ๋ฆฌ์†Œ์Šค"๊ฐ€ ํ‘œ์‹œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋“œ๋กœ์–ด ๋ธ”์—์„œ ํŒŒ์ผ์„ ์‚ญ์ œํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ์ด ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค ๐Ÿ‘

Mapsy์˜ ๋‹ต๋ณ€์€ https://stackoverflow.com/a/52750886์— ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ /node_modules/react-native/react.gradle ํŒŒ์ผ์„ ํŽธ์ง‘ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ์ˆ˜๋™์œผ๋กœ doFirst ๋ธ”๋ก ํ›„ doLast์˜ ๊ถŒ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

doFirst { ... }
doLast {
    def moveFunc = { resSuffix ->
        File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
            ant.move(file: originalDir, tofile: destDir);
        }
    }
    moveFunc.curry("ldpi").call()
    moveFunc.curry("mdpi").call()
    moveFunc.curry("hdpi").call()
    moveFunc.curry("xhdpi").call()
    moveFunc.curry("xxhdpi").call()
    moveFunc.curry("xxxhdpi").call()
}

๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@ Nextt1 ๋‹น์‹ ์€ ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ๊ณต๊ฐœ

๋ชจ๋‘ ์•ˆ๋…• - ํ™๋ณด ๋‚˜๋Š”์ด ํ•ฉ๋ณ‘ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ œ์•ˆํ•˜์ง€๋งŒ ๋ถ„๋ช…ํžˆ ํšŒ๊ท€์˜ ์›์ธ - https://github.com/facebook/react-native/issues/25325 - ๋‚ด๊ฐ€ ์กฐ์‚ฌ ๋งŒํ•˜๊ณ ์žˆ์–ด ์—ฌ๊ธฐ์— ์ง€๊ธˆ ์–ด๋–ค Gradle์„ ์ „๋ฌธ๊ฐ€๊ฐ€์žˆ๋Š” ๊ฒฝ์šฐ ํšŒ๊ท€๋ฅผ ์ผ์œผํ‚ค์ง€ ์•Š๊ณ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•, ๋„์›€์„ ์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค-๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

์ข‹์•„์š”, ์—ฌ๊ธฐ์— ๊ด€๋ จ๋œ PR์€ "revert PR"์„ ๊ฐ€์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค-๊ทธ๊ฒƒ์€ ํšŒ๊ท€๋ฅผ ์ผ์œผ ํ‚ต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ ์ด ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚จ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ œ๋Š” ์ •๋ง๋กœ ๋‚˜์œ ๋ฌธ์„œ์˜€์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ๋นŒ๋“œํ•˜๋Š” ๋™์•ˆ src ๋””๋ ‰ํ† ๋ฆฌ์— ํ•ญ๋ชฉ์„ ๋ณต์‚ฌํ•ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค. ๋ฌด์–ธ๊ฐ€๋ฅผ ์ค‘๊ฐ„์— ๋ณต์‚ฌํ•˜๊ณ  ์ƒ์„ฑํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฏธ src์— ๋ณต์‚ฌ ํ•œ ๊ฒฝ์šฐ (์ด ํŒจ์น˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์ „ ๋นŒ๋“œ์—์„œ ๋˜๋Š” react-native bundle ๋ช…๋ น์—์„œ) : src / main / res๋ฅผ ์ œ๊ฑฐํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ๊นจ๋—ํ•ฉ๋‹ˆ๋‹ค-ํ”„๋กœ์ ํŠธ์˜ ์‹ค์ œ ์ž์‚ฐ ๋งŒ

์ด์ œ ์˜คํ”„๋ผ์ธ ๋ฒˆ๋“ค๋กœ APK๋ฅผ ๋นŒ๋“œํ•˜๋ ค๋ฉด ๊ฐœ๋ฐœ์ž์—์„œ๋„ API <17์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์›น์˜ ๋ชจ๋“  ์‚ฌ์šฉ์ž๊ฐ€ ๊ถŒ์žฅํ•˜๋Š” ๊ฒƒ๊ณผ ๋‹ค๋ฅด๊ฒŒ ์ž‘์—…ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค (๋˜๋Š”์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค).

์›ํ•˜๋Š” ๊ฒƒ์€ android/app/build.gradle .

project.ext.react = [

        // This is what most people will need
        bundleInDebug: project.hasProperty("bundleInDebug") ? project.getProperty("bundleInDebug") : false,

        // If you use build variants it has to be like this - put your own names in there
        bundleInDevDebug: project.hasProperty("bundleInDevDebug") ? project.getProperty("bundleInDevDebug") : false,
        bundleInQaDebug: project.hasProperty("bundleInQaDebug") ? project.getProperty("bundleInQaDebug") : false,
        bundleInStagingDebug: project.hasProperty("bundleInStagingDebug") ? project.getProperty("bundleInStagingDebug") : false,
        bundleInProdDebug: project.hasProperty("bundleInProdDebug") ? project.getProperty("bundleInProdDebug") : false
]

๊ทธ๋Ÿฐ ๋‹ค์Œ react-native ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค-ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด gradle ํ”„๋กœ์ ํŠธ ์†์„ฑ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค.
ORG_GRADLE_PROJECT_bundleInDebug=true npx react-native run-android

(๋˜๋Š” ORG_GRADLE_PROJECT_bundleInDevDebug=true npx react-native run-android --variant devDebug ์™€ ๊ฐ™์€ ๋ณ€ํ˜•์˜ ๊ฒฝ์šฐ)

macOS 10.14.3 + RN 0.57.8 + Android Studio 3.3 + Gradle 4.10.3์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ์ „ํžˆ ์ด๊ฒƒ์„๋ณด๊ณ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์œ ์ผํ•œ ์‚ฌ๋žŒ์ด ์•„๋‹๊นŒ์š”? ์•„๋‹ˆ๋ฉด ์—ฌ๊ธฐ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋” ๋งŽ์ด ํŒŒ๊ณ  ์‹ค์ œ๋กœ ์ˆ˜์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ €๋Š” ํ˜„์žฌ @mkchx ( .txt ์ ‘๋ฏธ์‚ฌ๊ฐ€ ์ถ”๊ฐ€๋˜์–ด github์—์„œ ์ฒจ๋ถ€ ํŒŒ์ผ์„ ํ—ˆ์šฉ ํ•จ) ์˜ ์œ„ ์ฃผ์„ ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฒจ๋ถ€ ๋œ ํŒจ์น˜์™€ ํ•จ๊ป˜ "patch-package"ํŒจํ‚ค์ง€ ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋™์œผ๋กœ ์ž‘์—…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด package.json ์Šคํฌ๋ฆฝํŠธ์— postinstall: patch-package ์„ ์ถ”๊ฐ€ ํ•œ ํ›„ 'npm install'์—์„œ ์ˆ˜์ •ํ•˜์‹ญ์‹œ์˜ค.

๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ์œ ์šฉ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค ...
react-native + 0.57.8.patch.txt

๋Œ€๋ฐ•! ์ง€๊ธˆ์€ ์ตœ๊ณ ์˜ ๋‹ต๋ณ€์ž…๋‹ˆ๋‹ค!

0.59.9์—์„œ ์—ฌ์ „ํžˆ ์ด๊ฒƒ์„๋ณด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. @mkchx ์˜ ๋Œ€๋‹ต์€ ๋‚˜๋ฅผ ์œ„ํ•ด ๋ฌธ์ œ๋ฅผ ๋ถ„๋ฅ˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

@juliancorrea @scgough ๊ทธ๋ƒฅ ์กฐ์‹ฌํ•˜์„ธ์š”. PR๋„ ๋ฐ›์•„ ๋“ค์—ฌ ์†”๋ฃจ์…˜ ์Šคํƒ€์ผ์„ ๋๊นŒ์ง€ ๋”ฐ๋ž์ง€๋งŒ ํ›„์† ๋ฌธ์ œ ํ›„์—๋Š” ๋˜๋Œ๋ฆด ํ•„์š”๊ฐ€์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋ง‰ ๋‹ค๋ฅธ ํ•ด๊ฒฐ์ฑ…์ž…๋‹ˆ๋‹ค. ์œ„์˜ ๋ช‡ ๊ฐ€์ง€ ์˜๊ฒฌ์— ํ˜„์žฌ ๊ถŒ์žฅ๋˜๋Š” ์†”๋ฃจ์…˜์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ๊ฒŒ์‹œํ–ˆ์œผ๋ฉฐ ์ƒˆ๋กœ์šด ์Šคํƒ€์ผ ๋งŒ ์ถ”์ฒœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. @mkchx ๋‹ต๋ณ€์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ์ด์ „ ์ฒจ๋ถ€ ํŒจ์น˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํ˜„์žฌ๋กœ์„œ๋Š” ์ž‘๋™ํ•˜์ง€๋งŒ ํŠน์ • ์กฐ๊ฑด์—์„œ๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ์— ํ–ฅํ›„ ํ•„์š”ํ•  ์ˆ˜์žˆ๋Š” ๋‹ค๋ฅธ ์ผ๋ฐ˜์ ์ธ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

@mikehardy OK- ์ด์ œ ํ•ด๊ฒฐ์ฑ…์„ ์‚ดํŽด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
๋‚ด๊ฐ€ ์‹ค์ œ๋กœ ์›ํ•˜๋Š” ๊ฒƒ์€ Android Studio์˜ ์„œ๋ช… ๋œ APK ๋นŒ๋“œ๊ฐ€ ๋ฒˆ๋“ค์„ ๊ฑด๋„ˆ ๋›ฐ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค (ํ„ฐ๋ฏธ๋„์„ ํ†ตํ•ด ์ˆ˜๋™์œผ๋กœ ์ˆ˜ํ–‰).
์ œ๊ณต ํ•œ ์„ค์ •์„ ์‚ดํŽด๋ณด๊ณ  ๋„์›€์ด๋˜๋Š”์ง€ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์•„์ง ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค ...
๋ฆด๋ฆฌ์Šค APK ํŒŒ์ผ์„ ๋งŒ๋“ค ์ˆ˜์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ์ž์‚ฐ ํŒŒ์ผ์— ๋Œ€ํ•ด ๋‹ค์Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

[drawable-mdpi-v4/filename] /Users/me/React/myapp/android/app/src/main/res/drawable-mdpi/filename.png
[drawable-mdpi-v4/filename] /Users/me/React/myapp/android/app/build/generated/res/react/release/drawable-mdpi/filename.png : ์˜ค๋ฅ˜ : ์ค‘๋ณต ๋ฆฌ์†Œ์Šค

drawable-mdpi ํด๋”์˜ ๋‘ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ชจ๋‘ ์‚ญ์ œํ–ˆ์ง€๋งŒ APK ์ƒ์„ฑ์œผ๋กœ ์ธํ•ด ๋‹ค์‹œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
๋ฒˆ๋“ค์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ์„ ์ˆ˜๋™์œผ๋กœ ์‹คํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/

๋‚ด ์•ฑ gradle์—๋Š” ๋‹ค์Œ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

project.ext.react = [
    entryFile: "index.android.js",
    bundleInRelease: true    //I've tried true and false here
]

apply from: "../../node_modules/react-native/react.gradle"

์ถ”๊ฐ€ ์ •๋ณด์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ-๋‚ด ์•ฑ์ด ๋””๋ฒ„๊ทธ์—์„œ ์ž˜ ๋นŒ๋“œ๋ฉ๋‹ˆ๋‹ค ( react-native run-android ).
ํ˜„์žฌ ๋ฆด๋ฆฌ์Šค APK๋ฅผ ๋นŒ๋“œ ํ•  ์ˆ˜์žˆ๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์€ ์œ„์˜ doLast ๋˜๋Œ๋ฆฌ๊ธฐ PR ์ˆ˜์ •์„ ํ†ตํ•ด์„œ์ž…๋‹ˆ๋‹ค.

์ ์–ด๋„ ๋‚ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ด์œ  / ํ•ด๊ฒฐ์ฑ…์ด์žˆ์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋‚ด ์ด์ „ ๋ฒˆ๋“ค ๋ช…๋ น (RN 0.2.x๋ถ€ํ„ฐ ์‚ฌ์šฉ ํ–ˆ์Šต๋‹ˆ๊นŒ?!)์ด ์ž์‚ฐ์„ ๋Œ€์ƒ ํด๋” android/app/src/main/res/ ํ‘ธ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜ ๋งํฌ์—์„œ> RN 57์—๋Š” ์‹ค์ œ๋กœ ์ž์‚ฐ์„ ๋‹ค์Œ ํด๋”๋กœ ํ‘ธ์‹œํ•ด์•ผํ•œ๋‹ค๋Š” ๊ฒŒ์‹œ๋ฌผ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
android/app/build/intermediates/res/merged/release/

์ถœ์ฒ˜ : https://github.com/facebook/react-native/issues/19211#issuecomment -448301870

๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ์‚ญ์ œ ๋œ drawable-mdpi ์— ๋ณต์‚ฌํ–ˆ๋‹ค ์ž์‚ฐ android/app/src/main/res/
  • ์ƒˆ ํด๋” ์œ„์น˜๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ฒˆ๋“ค ๋ช…๋ น์„ ์—…๋ฐ์ดํŠธํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๋‚ด APK๊ฐ€ ์ด์ œ ๋นŒ๋“œ๋ฉ๋‹ˆ๋‹ค ... (_ I 'm about to test it_)

์ตœ์‹  ์ •๋ณด
APK๊ฐ€ ์„ค์น˜๋˜์—ˆ์ง€๋งŒ ๋‹ค์Œ ์˜ˆ์™ธ์™€ ํ•จ๊ป˜ ์•ฑ์ด ์ถฉ๋Œํ•ฉ๋‹ˆ๋‹ค.
com.facebook.react.bridge.JSApplicationIllegalArgumentException: Error while updating property 'defaultSrc' of a view managed by: RCTImageView

... ์ด๋ฏธ์ง€๋ฅผ ์ฐพ์„ ์ˆ˜์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ๐Ÿ˜ž

์—…๋ฐ์ดํŠธ 2
์ง€๊ธˆ๊นŒ์ง€ APK๊ฐ€ ์ž‘๋™ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • ์ž์‚ฐ์— ๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋ฒˆ๋“ค ํ˜ธ์ถœ์„ ๋˜๋Œ๋ฆฝ๋‹ˆ๋‹ค. android/app/src/main/res/
  • ๋ฒˆ๋“ค ๋ช…๋ น ์‹คํ–‰
  • android/app/src/main/res/drawable-mdpi ์„ android/app/src/main/res/drawable-hdpi ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.
  • ์„œ๋ช… ๋œ APK ๋นŒ๋“œ

๋‚ด ๋นŒ๋“œ gradle์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

project.ext.react = [
    entryFile: "index.android.js"
]

๊ทธ๋Ÿฌ๋ฉด APK๊ฐ€ ๋นŒ๋“œ๋˜๊ณ  ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ  :
์ด๋ฏธ์ง€ ์Šฌ๋ผ์ด๋” ๊ตฌ์„ฑ ์š”์†Œ์—์„œ createBitmap OutOfMemory ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.
๋‹ค์Œ์„ ๋งค๋‹ˆํŽ˜์ŠคํŠธ์— ์ถ”๊ฐ€ํ–ˆ๊ณ  ์•ฑ์ด ๋‹ค์‹œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. android:largeHeap="true"
์ถ”๊ฐ€๊ฐ€ ๋ˆ„์ˆ˜ / ๊ตฌ์„ฑ ์š”์†Œ ๋ฌธ์ œ๋ฅผ ์šฐํšŒํ•˜๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ์ง€๊ธˆ๊นŒ์ง€ ์•ฑ์€ ๋ฌธ์ œ์—†์ด ๋‹ค์‹œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

React Native 0.60.0์—์„œ ๋„ค์ดํ‹ฐ๋ธŒ ๊ธฐ๋ฐ˜๋„ ์ค‘๋ณต ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€๋งŒ ์œ„์˜ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์›์‹œ ํด๋”๋ฅผ ๋Œ€์ƒ์œผ๋กœํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

[raw / node_modules_nativebase_dist_src_basic_icon_nbicons] C : Projectssome-appCLIENTandroidappsrcmainresrawnode_modules_nativebase_dist_src_basic_icon_nbicons.json
[raw / node_modules_nativebase_dist_src_basic_icon_nbicons] C : Projectssome-appCLIENTandroidappbuildgeneratedresreactreleaserawnode_modules_nativebase_dist_src_basic_icon_nbicons.json : ์˜ค๋ฅ˜ : ์ค‘๋ณต ๋ฆฌ์†Œ์Šค

์ด ๋ฌธ์ œ๊ฐ€์žˆ๋Š” ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์˜ ๊ฒฝ์šฐ :

        doLast {
            def moveFunc = { resSuffix ->
                File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");
                if (originalDir.exists()) {
                    File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
                    ant.move(file: originalDir, tofile: destDir);
                }
            }

            moveFunc.curry("ldpi").call()
            moveFunc.curry("mdpi").call()
            moveFunc.curry("hdpi").call()
            moveFunc.curry("xhdpi").call()
            moveFunc.curry("xxhdpi").call()
            moveFunc.curry("xxxhdpi").call()

            File originalDir = file("$buildDir/generated/res/react/release/raw");
                if (originalDir.exists()) {
                    File destDir = file("$buildDir/../src/main/res/raw");
                    ant.move(file: originalDir, tofile: destDir);
            }
        }

CI๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ œ ๊ฒฝ์šฐ์—๋Š” raw ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ๋ฌธ์ œ๊ฐ€ ์ง€์†๋ฉ๋‹ˆ๋‹ค.

๋ฒ„์ „ : react-native 0.59.5

๋‚ด ์†”๋ฃจ์…˜ :

doLast {                                                                                            
  def moveFunc = { resSuffix ->                                                                   
    File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");     
    if (originalDir.exists()) {                                                                 
      File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");                 
      ant.move(file: originalDir, tofile: destDir);                                           
    }
  } 
  def moveRawFunc = { dir ->                                                                   
    File originalDir = file("$buildDir/generated/res/react/release/${dir}");     
    if (originalDir.exists()) {                                                                 
      File destDir = file("$buildDir/../src/main/res/${dir}");                 
      ant.move(file: originalDir, tofile: destDir);                                           
    }
  }  
  moveFunc.curry("ldpi").call()
  moveFunc.curry("mdpi").call()
  moveFunc.curry("hdpi").call()
  moveFunc.curry("xhdpi").call()
  moveFunc.curry("xxhdpi").call()
  moveFunc.curry("xxxhdpi").call()
  moveRawFunc.curry("raw").call()
}

๋ฌธ์•ˆ ์ธ์‚ฌ

์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค!

[drawable-mdpi-v4/node_modules_reactnativemaplink_src_images_uber] /Users/umair/my-app/android/app/src/main/res/drawable-mdpi/node_modules_reactnativemaplink_src_images_uber.png   [drawable-mdpi-v4/node_modules_reactnativemaplink_src_images_uber] /Users/umair/my-app/android/app/build/generated/res/react/debug/drawable-mdpi/node_modules_reactnativemaplink_src_images_uber.png: Error: Duplicate resources

react-native run-android ์‹คํ–‰ํ•  ๋•Œ์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€๋งŒ ๋ฆด๋ฆฌ์Šค ๋นŒ๋“œ๋ฅผ ๋นŒ๋“œํ•˜๊ณ  ์‹คํ–‰ํ•  ๋•Œ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์œ„์˜ ์†”๋ฃจ์…˜ ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ๋‚˜๋ฅผ ์œ„ํ•ด ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

RN 0.60.5

์—…๋ฐ์ดํŠธ : ๋‚˜๋Š” release ๋””๋ ‰ํ† ๋ฆฌ ๋Œ€์‹  debug ์„ ์ธ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์œ„์˜ "ํŒจ์น˜"๋ฉ”์†Œ๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์•ผํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜๊ณ  ๊ทธ๊ฒƒ์„ ๊ณ ์ณค์Šต๋‹ˆ๋‹ค. ์ €๋„ raw ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ˆ˜์ •ํ•ด์•ผํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋˜ํ•œ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฉฐ react.gradle ํŒจ์น˜๋กœ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ œ ๊ฒฝ์šฐ ์ค‘๋ณต ๋œ ๋ฆฌ์†Œ์Šค๋Š” .OBJ ๋ฐ .MTL ํŒŒ์ผ์ด๋ฉฐ ์ด๋ฏธ์ง€ ๋ฆฌ์†Œ์Šค์— ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

[raw / assets_res_salad_salad] /Users/sercanov/Projects/ARt/diner/DinerApp/android/app/src/main/res/raw/assets_res_salad_salad.mtl [raw / assets_res_salad_salad] / Users / sercanov / Projects / ARt / diner / DinerApp /android/app/src/main/res/raw/assets_res_salad_salad.obj : ์˜ค๋ฅ˜ : ์ค‘๋ณต ๋ฆฌ์†Œ์Šค
[raw / assets_res_steak_steak] /Users/sercanov/Projects/ARt/diner/DinerApp/android/app/src/main/res/raw/assets_res_steak_steak.mtl [raw / assets_res_steak_steak] / Users / sercanov / Projects / ARt / diner / DinerApp /android/app/src/main/res/raw/assets_res_steak_steak.obj : ์˜ค๋ฅ˜ : ์ค‘๋ณต ๋ฆฌ์†Œ์Šค
[raw / assets_res_salmon_salmon] /Users/sercanov/Projects/ARt/diner/DinerApp/android/app/src/main/res/raw/assets_res_salmon_salmon.mtl [raw / assets_res_salmon_salmon] / Users / sercanov / Projects / ARt / diner / DinerApp /android/app/src/main/res/raw/assets_res_salmon_salmon.obj : ์˜ค๋ฅ˜ : ์ค‘๋ณต ๋ฆฌ์†Œ์Šค

@sercanov ์—ฌ์ „ํžˆ src์— ๋Œ€ํ•œ ์‚ฌ๋ณธ์„ ์‚ฌ์šฉํ•˜๋ ค๊ณ ํ•ฉ๋‹ˆ๊นŒ? ์ด ์Šคํƒ€์ผ์€ ์กฐ์‚ฌ๋˜์—ˆ๊ณ  ์•Œ๋ ค์ง„ ์ด์œ ๋กœ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. src์— ๋ฌผ๊ฑด์„ ๋ฐฐ์น˜ํ•˜์ง€ ์•Š๋Š” ์ง€์›๋˜๋Š” ๋นŒ๋“œ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋‹ˆ๋ฉด non-src ๋ฐฉ์‹์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ์‹คํŒจํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? https://github.com/facebook/react-native/issues/22234#issuecomment -504721069

@mikehardy๋Š” ์‹ค์ œ๋กœ ๋‘ ๊ฐ€์ง€ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๋ชจ๋‘ ์‹œ๋„ํ–ˆ์ง€๋งŒ ๋‘˜ ๋‹ค ๋ฆด๋ฆฌ์Šค ๋นŒ๋“œ์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋””๋ฒ„๊ทธ ๋ชจ๋“œ btw์—์„œ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

not-copy-to-src ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ๋•Œ ORG_GRADLE_PROJECT_bundleInArRelease=true npx react-native run-android --variant arRelease ๋‚˜๋Š” ์ด๊ฒƒ์„ ์–ป์Šต๋‹ˆ๋‹ค;

': app : mergeArReleaseResources '์ž‘์—…์„ ์‹คํ–‰ํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.
[raw / assets_res_salad_salad] /Users/sercanov/Projects/ARt/diner/DinerApp/android/app/build/generated/res/react/ar/release/raw/assets_res_salad_salad.mtl [raw / assets_res_salad_salad] / Users / sercanov / Projects /ARt/diner/DinerApp/android/app/build/generated/res/react/ar/release/raw/assets_res_salad_salad.obj : ์˜ค๋ฅ˜ : ์ค‘๋ณต ๋ฆฌ์†Œ์Šค
[raw / assets_res_steak_steak] /Users/sercanov/Projects/ARt/diner/DinerApp/android/app/build/generated/res/react/ar/release/raw/assets_res_steak_steak.mtl [raw / assets_res_steak_steak] / Users / sercanov / Projects /ARt/diner/DinerApp/android/app/build/generated/res/react/ar/release/raw/assets_res_steak_steak.obj : ์˜ค๋ฅ˜ : ์ค‘๋ณต ๋ฆฌ์†Œ์Šค
[raw / assets_res_salmon_salmon] /Users/sercanov/Projects/ARt/diner/DinerApp/android/app/build/generated/res/react/ar/release/raw/assets_res_salmon_salmon.mtl [raw / assets_res_salmon_salmon] / Users / sercanov / Projects /ARt/diner/DinerApp/android/app/build/generated/res/react/ar/release/raw/assets_res_salmon_salmon.obj : ์˜ค๋ฅ˜ : ์ค‘๋ณต ๋ฆฌ์†Œ์Šค

์‚ฌ์šฉ์‹œ src๋กœ ๋ณต์‚ฌ doLast ๋ฐฉ๋ฒ•; ์„ฑ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ๋นŒ๋“œ ํ•  ๋•Œ๋งˆ๋‹ค android / build ํด๋”๋ฅผ ์ง€์›Œ์•ผํ–ˆ์ง€๋งŒ ์–ด๋–ป๊ฒŒ ๋“  ์•ฑ์—์„œ ์ž์‚ฐ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํ˜„์žฌ ์กฐ์‚ฌ์ค‘์ธ ๋‚ด ์ฝ”๋“œ์™€ ๊ด€๋ จ์ด์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

not-copy-to-src ๋ฐฉ์‹์œผ๋กœ ์ „ํ™˜ ํ•  ๋•Œ ๋จผ์ € ๋ชจ๋“  ๊ฒƒ์„ ์ •๋ฆฌํ•˜์—ฌ ์ „ํ™˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ํ”„๋กœ์ ํŠธ์—๋Š” ์ด์ „์˜ copy-to-src ์Šคํƒ€์ผ์˜ ๋ฒˆ๋“ค๋ง ๊ด€์ ์—์„œ ๋งŽ์€ "์“ฐ๋ ˆ๊ธฐ"๊ฐ€ ์žˆ์—ˆ๋Š”๋ฐ, ์ž‘์—… ์ „์— ์ •๋ฆฌํ•ด์•ผํ–ˆ์ง€๋งŒ ๋งค๋ฒˆ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค.

@ rahulkumar1409 ์ด๊ฒƒ์€์ด ์˜ค๋ฅ˜์—์„œ ๋‚˜๋ฅผ ๋„์™”์ง€๋งŒ ๋‹ค๋ฅธ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ž‘์—… : react-native-simple-download- manager : verifyReleaseResources FAILED

์™œ ์ด๋Ÿฐ ์ผ์ด ๋ฐœ์ƒํ•˜๋Š”์ง€ ์•„์‹ญ๋‹ˆ๊นŒ?

์ด ์†”๋ฃจ์…˜์€ ์ €์—๊ฒŒ ํšจ๊ณผ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ /node_modules/react-native/react.gradle ํŒŒ์ผ์„ ํŽธ์ง‘ํ•ฉ๋‹ˆ๋‹ค.
doFirst ๋ธ”๋ก ๋ฐ”๋กœ ๋’ค์— doLast๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

doFirst {...}
doLast {
def moveFunc = {resSuffix->
ํŒŒ์ผ originalDir = file ( "$ buildDir / generated / res / react / release / drawable-$ {resSuffix}");
if (originalDir.exists ()) {
ํŒŒ์ผ destDir = file ( "$ buildDir /../ src / main / res / drawable-$ {resSuffix}");
ant.move (ํŒŒ์ผ : originalDir, tofile : destDir);
}
}
moveFunc.curry ( "ldpi"). call ()
moveFunc.curry ( "mdpi"). call ()
moveFunc.curry ( "hdpi"). call ()
moveFunc.curry ( "xhdpi"). call ()
moveFunc.curry ( "xxhdpi"). call ()
moveFunc.curry ( "xxxhdpi"). call ()
}

์šฐ๋ฆฌ๋Š” ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ 0.60.5์— ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” @mikehardy๊ฐ€ ์–ธ๊ธ‰ ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์€ ์ œํ’ˆ ๋ง›์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ @Dbroqua๊ฐ€ ๊ฒฝํ—˜ ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ 'raw'ํด๋”์— ๋ฌธ์ œ๊ฐ€์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ ๋‘ ์†”๋ฃจ์…˜์„ ํ˜ผํ•ฉํ•˜๊ณ  ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

doLast {
    def moveFunc = { resSuffix ->
        File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/drawable-${resSuffix}")
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}")
            ant.move(file: originalDir, tofile: destDir)
        }
    }
    def moveRawFunc = { dir ->
        File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/${dir}")
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/${dir}")
            ant.move(file: originalDir, tofile: destDir)
        }
    }

    moveFunc.curry("ldpi").call()
    moveFunc.curry("mdpi").call()
    moveFunc.curry("hdpi").call()
    moveFunc.curry("xhdpi").call()
    moveFunc.curry("xxhdpi").call()
    moveFunc.curry("xxxhdpi").call()
    moveRawFunc.curry("raw").call()
}

์ด ์Šค๋ ˆ๋“œ๋Š” ๊ธฐ์—ฌํ•ด ์ฃผ์‹  ๋ชจ๋“  ๋ถ„๋“ค๊ป˜ ์ •๋ง ๋„์›€์ด๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ˜„

๋ฆด๋ฆฌ์Šค ๋นŒ๋“œ์—์„œ๋งŒ ์ค‘๋ณต ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. react-native 60.5๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

/release/drawable-xhdpi/node_modules_reactnavigationstack_lib_module_views_assets_backicon.png : ์˜ค๋ฅ˜ : ์ค‘๋ณต ๋ฆฌ์†Œ์Šค

bundleInDebug๋ฅผ true ๋ฐ false๋กœ ์„ค์ •ํ–ˆ์ง€๋งŒ ์•„๋ฌด๋Ÿฐ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์•ฑ ์„ผํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ์ถ• ์ค‘์ด๋ฉฐ src / main / assets / appcenter-config.json ํŒŒ์ผ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ง€์ • ๊ธ€๊ผด์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ src / main / assets / fonts ๋””๋ ‰ํ† ๋ฆฌ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฌธ์ œ์˜ ์›์ธ ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

@ARichIVC ๋ฌธ์ œ๋Š” ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์— ์ฐธ์กฐ ๋œ ํŒŒ์ผ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ด ์›๋ž˜ ์†”๋ฃจ์…˜์˜ ํ‘œ์ค€ "๋‚ด src / ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์ด์ „ ๋ณต์‚ฌ ์Šคํƒ€์ผ์˜ ๋ฒˆ๋“ค ํŒจํ‚ค์ง• ์‹œ๋„๋กœ ์ธํ•ด ์˜ค์—ผ๋˜์—ˆ์Šต๋‹ˆ๋‹ค"๋ฌธ์ œ๊ฐ€ ๋ง‰ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์ด๋ผ๋Š” ๊ฒƒ์„ ๋ชจ๋‘ ์ธ์‹ํ•˜๊ธฐ ์ „์— ๋ณต์‚ฌ ๋œ ๊ฒƒ์—์„œ src /๋ฅผ ์ง€์›Œ์•ผํ•ฉ๋‹ˆ๋‹ค. bundleInDebug ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ›„์† ์†”๋ฃจ์…˜์„ ์‹œ๋„ํ•˜๊ธฐ ์ „์— ์ผ. ์•ˆํƒ€๊น๊ฒŒ๋„ ๋‹ค๋ฃจ๊ธฐ ์–ด๋ ต๊ณ  ๊ธด ๋ชจ๋“  ๊ฒƒ์ด์ด ์Šค๋ ˆ๋“œ์— ์žˆ์ง€๋งŒ ์ •๋ณด๋Š” ๊ฑฐ๊ธฐ์— ์žˆ์Šต๋‹ˆ๋‹ค.

๋„์›€์„ ์ฃผ์‹  @mikehardy ์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์ž์‚ฐ ๋””๋ ‰ํ† ๋ฆฌ์˜ ๊ธ€๊ผด ๋“ฑ์„ ๊ทธ๋Œ€๋กœ ๋‘๋Š” ๊ฒƒ์ด ์ข‹์ง€๋งŒ ์ฃผ์œ„์— ๋งค๋‹ฌ๋ ค์žˆ๋Š” ๋‹ค๋ฅธ ๋น„ํŠธ์™€ ์กฐ๊ฐ์„ ์‚ญ์ œํ•ด์•ผํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. ์ฆ‰ androidappsrcmainresdrawable-hdpi์˜ ๋ชจ๋“  ๊ฒƒ

๊ธ€๊ผด์˜ ๊ฒฝ์šฐ์—๋„ ์˜ฌ๋ฐ”๋ฅธ ๋””๋ ‰ํ† ๋ฆฌ์— ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ : https://github.com/oblador/react-native-vector-icons#android ์ด ํŒŒ์ผ์„ ํ˜ธ์ถœํ•˜์—ฌ ๋น„ src๋กœ ์‹ ์ค‘ํ•˜๊ฒŒ ๋ณต์‚ฌํ•˜๋„๋ก ์ง€์‹œํ•ฉ๋‹ˆ๋‹ค. ๋””๋ ‰ํ† ๋ฆฌ https://github.com/oblador/react-native-vector-icons/blob/master/fonts.gradle#L16- ๋ชจ๋“  ์‚ฌ๋žŒ์˜ ํ”„๋กœ์ ํŠธ๋Š” ๋ฌผ๋ก  ๋‹ค๋ฅด์ง€๋งŒ ์–ธ๊ธ‰ ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ 0.60.5์— ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” @mikehardy๊ฐ€ ์–ธ๊ธ‰ ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์€ ์ œํ’ˆ ๋ง›์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ @Dbroqua๊ฐ€ ๊ฒฝํ—˜ ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ 'raw'ํด๋”์— ๋ฌธ์ œ๊ฐ€์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ ๋‘ ์†”๋ฃจ์…˜์„ ํ˜ผํ•ฉํ•˜๊ณ  ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

doLast {
    def moveFunc = { resSuffix ->
        File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/drawable-${resSuffix}")
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}")
            ant.move(file: originalDir, tofile: destDir)
        }
    }
    def moveRawFunc = { dir ->
        File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/${dir}")
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/${dir}")
            ant.move(file: originalDir, tofile: destDir)
        }
    }

    moveFunc.curry("ldpi").call()
    moveFunc.curry("mdpi").call()
    moveFunc.curry("hdpi").call()
    moveFunc.curry("xhdpi").call()
    moveFunc.curry("xxhdpi").call()
    moveFunc.curry("xxxhdpi").call()
    moveRawFunc.curry("raw").call()
}

์ด ์Šค๋ ˆ๋“œ๋Š” ๊ธฐ์—ฌํ•ด ์ฃผ์‹  ๋ชจ๋“  ๋ถ„๋“ค๊ป˜ ์ •๋ง ๋„์›€์ด๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ˜„

ํšจ๊ณผ๊ฐ€์žˆ๋‹ค! ๋งŽ์€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๐Ÿ‘

react native 0.59.1 ์ด์ƒ์˜ ๊ฒฝ์šฐ node_modules / react-native์˜ react.gradle์— ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ์—์„œ ๋ง›์„ ๋‚ธ ์‚ฌ์šฉ์„ ์œ„ํ•ด.

        def flavorPathSegment = ""
        android.productFlavors.all { flavor ->
            if (targetName.toLowerCase().contains(flavor.name)) {
                flavorPathSegment = flavor.name
           }
        }
        doLast {
            def moveFunc = { resSuffix ->
                File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}/release/drawable-${resSuffix}");
                if (originalDir.exists()) {
                    File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
                    ant.move(file: originalDir, tofile: destDir);
                }
            }
            moveFunc.curry("ldpi").call()
            moveFunc.curry("mdpi").call()
            moveFunc.curry("hdpi").call()
            moveFunc.curry("xhdpi").call()
            moveFunc.curry("xxhdpi").call()
            moveFunc.curry("xxxhdpi").call()
        }

@ dayachand-systematix์ด ๋‚˜์œ ์กฐ์–ธ. ๊ทธ ์Šคํƒ€์ผ ์†”๋ฃจ์…˜์€ PR์ด ์žˆ๊ณ  ์‹ฌ์ง€์–ด ๋ณ‘ํ•ฉ๋˜๋Š” ์ง€์ ๊นŒ์ง€ ์ถ”๊ตฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ž˜๋ชป๋œ ๋ฐฉํ–ฅ์ž„์„ ๋ฐœ๊ฒฌํ•˜๊ณ  PR์„ ๋˜๋Œ ๋ ธ์Šต๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์—๊ฒŒ PR ๋ณ‘ํ•ฉ์„ ์‹ค์ œ๋กœ ๋˜ ๋Œ๋ฆฐ ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜๋„๋ก ์กฐ์–ธ ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ๋‚ด๊ฐ€ ์•Š์„ ๊ฒƒ. https://github.com/facebook/react-native/issues/22234#issuecomment -504721069

@mikehardy ์˜ˆ, ์ด๊ฒƒ์ด ์˜๊ตฌ์  ์ธ ํ•ด๊ฒฐ์ฑ…์€ ์•„๋‹ˆ์ง€๋งŒ ์ž˜ ์ž‘๋™ res ๋””๋ ‰ํ† ๋ฆฌ์— ์Šคํ”Œ๋ž˜์‹œ ํ™”๋ฉด ๋ฐ DB์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ํŒŒ์ผ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์˜ˆ @ dayachand-systematix ์ €๋„ :

mike<strong i="6">@isabela</strong>:~/work/Kullki/ksocialscore/packages/public-app/android/app (lerna-import) % find . -type f |grep res
./src/main/res/drawable-xhdpi/minilogo_bw.png
./src/main/res/mipmap-xxhdpi/ic_launcher.png
./src/main/res/values-v21/styles.xml
./src/main/res/drawable-xxhdpi/minilogo_bw.png
./src/main/res/drawable-xxhdpi/kscore_splash.png
./src/main/res/drawable-hdpi/minilogo_bw.png
./src/main/res/mipmap-xxxhdpi/ic_launcher.png
./src/main/res/mipmap-hdpi/ic_launcher.png
./src/main/res/layout/launch_screen.xml
./src/main/res/drawable/background_launch.xml
./src/main/res/values/colors.xml
./src/main/res/values/styles.xml
./src/main/res/values/strings.xml
./src/main/res/mipmap-xhdpi/ic_launcher.png
./src/main/res/xml/filepaths.xml
./src/main/res/xml/react_native_config.xml
./src/main/res/drawable-mdpi/minilogo_bw.png
./src/main/res/drawable-xxxhdpi/minilogo_bw.png
./src/main/res/mipmap-mdpi/ic_launcher.png
./src/qa/res/mipmap-xxhdpi/ic_launcher.png
./src/qa/res/mipmap-xxxhdpi/ic_launcher.png
./src/qa/res/mipmap-hdpi/ic_launcher.png
./src/qa/res/values/strings.xml
./src/qa/res/mipmap-xhdpi/ic_launcher.png
./src/qa/res/mipmap-mdpi/ic_launcher.png
./src/debug/res/xml/react_native_config.xml
./src/staging/res/mipmap-xxhdpi/ic_launcher.png
./src/staging/res/mipmap-xxxhdpi/ic_launcher.png
./src/staging/res/mipmap-hdpi/ic_launcher.png
./src/staging/res/values/strings.xml
./src/staging/res/mipmap-xhdpi/ic_launcher.png
./src/staging/res/mipmap-mdpi/ic_launcher.png
./src/dev/res/mipmap-xxhdpi/ic_launcher.png
./src/dev/res/mipmap-xxxhdpi/ic_launcher.png
./src/dev/res/mipmap-hdpi/ic_launcher.png
./src/dev/res/values/strings.xml
./src/dev/res/mipmap-xhdpi/ic_launcher.png
./src/dev/res/mipmap-mdpi/ic_launcher.png

๊ทธ๋ฆฌ๊ณ  ์—ฌ์ „ํžˆ ์ œ์•ˆ ๋œ / ๋น„ PR ๋˜ ๋Œ๋ฆฐ ์†”๋ฃจ์…˜์ด ๋‚˜๋ฅผ ์œ„ํ•ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. : man_shrugging :

Heya, --asset-dest ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle

@ hery-finimize hi- --asset-dest ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์ œ๊ฑฐํ•˜์ง€ ์•Š์œผ๋ฉด ์ตœ์‹  ์ž์‚ฐ์ด ์˜ฌ๋ฐ”๋ฅธ ์œ„์น˜์— ๋ฒˆ๋“ค๋กœ ์ œ๊ณต๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ APK๋ฅผ ๋งŒ๋“ค ๋•Œ ๋ˆ„๋ฝ๋˜๊ฑฐ๋‚˜ ๋ˆ„๋ฝ ๋  ์œ„ํ—˜์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์•ฑ์˜ ๋‚ ์งœ ์ž์‚ฐ ํŒŒ์ผ?

@scgough ๋‚˜๋Š” ๊ทธ๋Ÿด ์ˆ˜๋„ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด Android Studio๋กœ ๋นŒ๋“œํ•˜๊ธฐ ์ „์— ํ•„์š”ํ•œ ๋กœ์ปฌ ์ž์‚ฐ์„ ์ œ์™ธํ•œ ๋ชจ๋“  ์ค‘๋ณต ์ž์‚ฐ์„ ์„ ํƒ์ ์œผ๋กœ ์ œ๊ฑฐ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

find android/app/src/main/res/drawable-* \( -name launch_screen.png -o -name ic_stat_onesignal_default.png -prune \) -o -type f -exec rm {} +

์ด์ƒ์ ์ด์ง€๋Š” ์•Š์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ ๋  ๋•Œ๊นŒ์ง€ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋Š” ์ž์‚ฐ ํด๋”์— ๊ฐ™์€ ์ด๋ฆ„๊ณผ ๋‹ค๋ฅธ ํ™•์žฅ์ž ํŒŒ์ผ์ด์žˆ๋Š” ๊ฒฝ์šฐ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

back.png
back.jpg

์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ๋Š” ๋‘˜ ๋‹ค ๊ทธ๋ ‡๊ฒŒ ๋ถ€๋ฅด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

R.drawable.back
R.drawable.back

ํŒŒ์ผ ์ค‘ ํ•˜๋‚˜๋ฅผ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ ์ด๋ฆ„์„ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š”,
react.gradle ์ˆ˜์ •์„ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋นŒ๋“œ๊ฐ€ ํ•œ ๋‹จ๊ณ„ ๋” ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค (app.aab๋Š” ๋นŒ๋“œ์ด์ง€๋งŒ APK๋ฅผ ๋นŒ๋“œ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

Android Studio๋กœ APK๋ฅผ ๋นŒ๋“œํ•˜๋ ค๊ณ ํ–ˆ์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค (react.gradle ํŒจ์น˜ ํฌํ•จ).
๋‘ ๊ฒฝ์šฐ ๋ชจ๋‘ APK๋ฅผ ๋นŒ๋“œํ•˜๋Š” ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋™์ผํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‚˜์—๊ฒŒ๋Š” ๋งค์šฐ ์ด์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ž˜๋ชป ?

์ด ์ฃผ์„์€ 0.59.10์—์„œ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์š”์  ๊ณผ ํ˜ผํ•ฉ.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค, @ dayachand-systematix!

๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ•œ ๊ฒƒ์€ ๋‘ ๊ฐ€์ง€ ์˜๊ฒฌ์˜ ์กฐํ•ฉ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋„๋ก ์—ฌ๊ธฐ์— ๋ถ™์—ฌ ๋„ฃ์Šต๋‹ˆ๋‹ค.

```
def flavorPathSegment = ""
android.productFlavors.all {๋ง›->
if (targetName.toLowerCase (). contains (flavor.name)) {
flavorPathSegment = flavor.name
}
}

        doLast {
            def moveFunc = { resSuffix ->
                File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/drawable-${resSuffix}")
                if (originalDir.exists()) {
                    File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}")
                    ant.move(file: originalDir, tofile: destDir)
                }
            }
            def moveRawFunc = { dir ->
                File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/${dir}")
                if (originalDir.exists()) {
                    File destDir = file("$buildDir/../src/main/res/${dir}")
                    ant.move(file: originalDir, tofile: destDir)
                }
            }

            moveFunc.curry("ldpi").call()
            moveFunc.curry("mdpi").call()
            moveFunc.curry("hdpi").call()
            moveFunc.curry("xhdpi").call()
            moveFunc.curry("xxhdpi").call()
            moveFunc.curry("xxxhdpi").call()
            moveRawFunc.curry("raw").call()
        }

@AbhishekNairOfficial ๋‹น์‹ ์€ ์ด๊ฒƒ์„ ์–ด๋””์— ๋„ฃ์Šต๋‹ˆ๊นŒ?

@AbhishekNairOfficial ๋‹น์‹ ์€ ์ด๊ฒƒ์„ ์–ด๋””์— ๋„ฃ์Šต๋‹ˆ๊นŒ?

node_modules / react-native / react.gradle.

์ด๊ฒƒ์„ doFirst () ๋ธ”๋ก ๋’ค์— ๋„ฃ์œผ์‹ญ์‹œ์˜ค.

@AbhishekNairOfficial ๋‹น์‹ ์€ ์ด๊ฒƒ์„ ์–ด๋””์— ๋„ฃ์Šต๋‹ˆ๊นŒ?

node_modules / react-native / react.gradle.

์ด๊ฒƒ์„ doFirst () ๋ธ”๋ก ๋’ค์— ๋„ฃ์œผ์‹ญ์‹œ์˜ค.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์ด ์•„๋‹Œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ๋‹ค์Œ npm install ์— ์žฌ์ •์˜๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์‹ฌ์ง€์–ด CI๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€ ์•„๋ž˜ ๋ช…๋ น์„ ์‹œ๋„ ํ–ˆ์Šต๋‹ˆ๊นŒ?

cd android
./gradlew clean
cd ..

๊ทธ๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ–ˆ์Šต๋‹ˆ๋‹ค

๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ•œ ๊ฒƒ์€ ๋‘ ๊ฐ€์ง€ ์˜๊ฒฌ์˜ ์กฐํ•ฉ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋„๋ก ์—ฌ๊ธฐ์— ๋ถ™์—ฌ ๋„ฃ์Šต๋‹ˆ๋‹ค.

def flavorPathSegment = ""
android.productFlavors.all { flavor ->
if (targetName.toLowerCase().contains(flavor.name)) {
                    flavorPathSegment = flavor.name
            }
            }

            doLast {
                def moveFunc = { resSuffix ->
                    File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/drawable-${resSuffix}")
                    if (originalDir.exists()) {
                        File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}")
                        ant.move(file: originalDir, tofile: destDir)
                    }
                }
                def moveRawFunc = { dir ->
                    File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/${dir}")
                    if (originalDir.exists()) {
                        File destDir = file("$buildDir/../src/main/res/${dir}")
                        ant.move(file: originalDir, tofile: destDir)
                    }
                }

                moveFunc.curry("ldpi").call()
                moveFunc.curry("mdpi").call()
                moveFunc.curry("hdpi").call()
                moveFunc.curry("xhdpi").call()
                moveFunc.curry("xxhdpi").call()
                moveFunc.curry("xxxhdpi").call()
                moveRawFunc.curry("raw").call()
            }

์˜ค ๋„Œ ๋‚ด ํ•˜๋ฃจ๋ฅผ ๊ตฌํ•ด ์คฌ์–ด <3

๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ•œ ๊ฒƒ์€ ๋‘ ๊ฐ€์ง€ ์˜๊ฒฌ์˜ ์กฐํ•ฉ์ด์—ˆ์Šต๋‹ˆ๋‹ค.
๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋„๋ก ์—ฌ๊ธฐ์— ๋ถ™์—ฌ ๋„ฃ์Šต๋‹ˆ๋‹ค.

def flavorPathSegment = ""
android.productFlavors.all { flavor ->
if (targetName.toLowerCase().contains(flavor.name)) {
                    flavorPathSegment = flavor.name
            }
            }

            doLast {
                def moveFunc = { resSuffix ->
                    File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/drawable-${resSuffix}")
                    if (originalDir.exists()) {
                        File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}")
                        ant.move(file: originalDir, tofile: destDir)
                    }
                }
                def moveRawFunc = { dir ->
                    File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/${dir}")
                    if (originalDir.exists()) {
                        File destDir = file("$buildDir/../src/main/res/${dir}")
                        ant.move(file: originalDir, tofile: destDir)
                    }
                }

                moveFunc.curry("ldpi").call()
                moveFunc.curry("mdpi").call()
                moveFunc.curry("hdpi").call()
                moveFunc.curry("xhdpi").call()
                moveFunc.curry("xxhdpi").call()
                moveFunc.curry("xxxhdpi").call()
                moveRawFunc.curry("raw").call()
            }

์˜ค ๋„Œ ๋‚ด ํ•˜๋ฃจ๋ฅผ ๊ตฌํ•ด ์คฌ์–ด <3

ํ•˜ํ•˜ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ฑฐ์˜ ๋งค์ผ์ด ์Šค๋ ˆ๋“œ์— ๊ณ„์† ์™”๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ๋„ ์‚ถ์„ ๋” ์‰ฝ๊ฒŒ ๋งŒ๋“ค๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

android/app/build ํด๋”๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๋‹ค์‹œ ๋นŒ๋“œํ•˜๋Š” ๊ฒƒ์ด ์ €์—๊ฒŒ ํšจ๊ณผ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ์†”๋ฃจ์…˜ :
/ your_project / android / app / src / main / raw / res์˜ ๋ชจ๋“  ํŒŒ์ผ ์„ ์‚ญ์ œ
๊ทธ๊ฒƒ์€ ๋‚˜๋ฅผ์œ„ํ•œ ์ผ์ž…๋‹ˆ๋‹ค!

๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ•œ ๊ฒƒ์€ ๋‘ ๊ฐ€์ง€ ์˜๊ฒฌ์˜ ์กฐํ•ฉ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋„๋ก ์—ฌ๊ธฐ์— ๋ถ™์—ฌ ๋„ฃ์Šต๋‹ˆ๋‹ค.

def flavorPathSegment = ""
android.productFlavors.all { flavor ->
if (targetName.toLowerCase().contains(flavor.name)) {
                    flavorPathSegment = flavor.name
            }
            }

            doLast {
                def moveFunc = { resSuffix ->
                    File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/drawable-${resSuffix}")
                    if (originalDir.exists()) {
                        File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}")
                        ant.move(file: originalDir, tofile: destDir)
                    }
                }
                def moveRawFunc = { dir ->
                    File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/${dir}")
                    if (originalDir.exists()) {
                        File destDir = file("$buildDir/../src/main/res/${dir}")
                        ant.move(file: originalDir, tofile: destDir)
                    }
                }

                moveFunc.curry("ldpi").call()
                moveFunc.curry("mdpi").call()
                moveFunc.curry("hdpi").call()
                moveFunc.curry("xhdpi").call()
                moveFunc.curry("xxhdpi").call()
                moveFunc.curry("xxxhdpi").call()
                moveRawFunc.curry("raw").call()
            }

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค @AbhishekNairOfficial. ๊ทธ๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ๋งŽ์€ ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ–ˆ์Šต๋‹ˆ๋‹ค.

rm -rf ./android/app/src/main/res/drawable-*
rm -rf ./android/app/src/main/res/raw

๋”ฐ๋ผ์„œ ์ด๊ฒƒ์€ ์ž‘๋™ํ•˜์ง€๋งŒ ์ด๋ฏธ์ง€๊ฐ€ ๋ˆ„๋ฝ๋˜์—ˆ์œผ๋ฏ€๋กœ ์•ฑ์„ ๋‹ค์‹œ ๋ฒˆ๋“ค๋กœ ๋งŒ๋“ค๋ฉด ๋™์ผํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์•„๋ฌด๋„ ์ด๊ฒƒ์— ๋Œ€ํ•œ ํ•ฉ๋ฒ•์  ์ธ ์ˆ˜์ •์ด ์žˆ์Šต๋‹ˆ๊นŒ?

v0.61.5์™€ @ wincod75 ๊ฐ€ ๋งํ–ˆ๋“ฏ์ด ๋ชจ๋“  ์ด๋ฏธ์ง€๊ฐ€ ์ œ๊ฑฐ๋˜๋ฏ€๋กœ raw ๋ฐ drawable ํด๋”๋ฅผ ์‚ญ์ œํ•˜๋Š” ๊ฒƒ์€ ์‹ค์ œ๋กœ ํ•ด๊ฒฐ์ฑ…์ด ์•„๋‹™๋‹ˆ๋‹ค.

๋ฆด๋ฆฌ์Šค ๋นŒ๋“œ๋ฅผ ์œ„ํ•ด ๋‹ค์‹œ ์ƒ์„ฑ๋˜์—ˆ์ง€๋งŒ react-native run-android --variant = release๋ฅผ ์‹คํ–‰ํ•  ๋•Œ๋„ ์ž‘๋™ํ•˜๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. .

๋ˆ„๊ตฌ๋“ ์ง€ v0.61.5์—์„œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๊นŒ?

@ gudbrand3 ๊ฒฐ๊ตญ ์œ„์—์„œ ์–ธ๊ธ‰ ํ•œ ์ˆ˜์ • ์‚ฌํ•ญ์„ "node_modules / react-native / react.gradle"ํŒŒ์ผ์— ๊ตฌํ˜„ํ•˜์—ฌ ์•ฑ ์Šคํ† ์–ด์— ์ƒˆ ๋นŒ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ์ด ์ž‘์—…์€ ํ„ฐ๋ฌด๋‹ˆ ์—†์Šต๋‹ˆ๋‹ค. ์•„์ง ์ˆ˜์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค ...

@ wincod75 ๋“ฃ๊ณ  ๋“ค์–ด! ๋‚˜๋„ ๋˜‘๊ฐ™์ด .. ์–ด์ฉŒ๊ตฌ. ์‚ฌ๋žŒ๋“ค์ด ์–ด์จŒ๋“  ์ˆ˜๋™์œผ๋กœ ๋๋‚ด๊ธฐ ๋•Œ๋ฌธ์— ๋” ๋‚˜์€ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์ฐพ์„ ๋•Œ๊นŒ์ง€ ํŒจํ‚ค์ง€์— ํฌํ•จ๋˜์ง€ ์•Š์€ ์ด์œ ๋ฅผ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด์ œ node_modules ๋ฐ re npm ์„ค์น˜๋ฅผ ์‚ญ์ œํ•  ๋•Œ๋งˆ๋‹ค ๋‹ค์‹œ ์ˆ˜ํ–‰ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. # ์ ˆ๋ง

์œ ์ง€ํ•ด์•ผํ•˜๋Š” ๋“œ๋กœ์–ด ๋ธ” ๋ฆฌ์†Œ์Šค๊ฐ€ ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋“œ๋กœ์–ด ๋ธ” ํด๋”๋ฅผ ์ œ๊ฑฐํ•˜๋ฉด ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด ๋ฌธ์ œ๋Š” android/app/src/main/res/raw ํด๋”์˜ ๋ชจ๋“  ํ•ญ๋ชฉ๊ณผ android/app/src/main/res/drawable ํด๋”์˜ nodemodules... ๋กœ ์‹œ์ž‘ํ•˜๋Š” ํŒŒ์ผ์— ๋Œ€ํ•œ duplicate resources ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

android/app/build.gradle :

...
project.ext.react = [
    ...
    bundleInRelease        : true,
    resourcesDirRelease   : "src/release/res",
    ...
]
...

node ์—์„œ android/app/src/main/drawable* node ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ชจ๋“  ํ•ญ๋ชฉ ์ œ๊ฑฐ :

rm android/app/src/main/drawable*/node*
rm -rf android/app/src/main/raw

ํ”„๋กœ์ ํŠธ๋ฅผ ์ •๋ฆฌํ•˜๊ณ  ๋ฐ˜์‘ ํ˜• ๊ธฐ๋ณธ ๋ฒˆ๋“ค ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์ง€ ๋ง๊ณ  ๋‹ค์‹œ ๋นŒ๋“œํ•˜์‹ญ์‹œ์˜ค.

์ด๊ฒƒ์ด ๋ˆ„๊ตฐ๊ฐ€๋ฅผ ๋•๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค!

์˜ค ์†Œ๋…„. ๊ณต์‹์ ์ธ ์ˆ˜์ •์ด ์ง„ํ–‰ ์ค‘์ผ๊นŒ์š”?

v.0.61.4์—์„œ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋‚˜์˜ ๊ฒฝ์šฐ์—๋Š”
์ฒซ์งธ : 'doFirst'๋’ค์— node_modules / react-native / react.gradle์— ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ๋ฐฐ์น˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

doLast {
    def moveFunc = { resSuffix ->
        File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
            ant.move(file: originalDir, tofile: destDir);
        }
    }
    moveFunc.curry("ldpi").call()
    moveFunc.curry("mdpi").call()
    moveFunc.curry("hdpi").call()
    moveFunc.curry("xhdpi").call()
    moveFunc.curry("xxhdpi").call()
    moveFunc.curry("xxxhdpi").call()
}

๋‘ ๋ฒˆ์งธ : android / app / src / main / res / raw ํด๋”์˜ ๋ชจ๋“  ๋‚ด์šฉ์„ ์‚ญ์ œํ–ˆ์Šต๋‹ˆ๋‹ค.
๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ์œ ์šฉ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

์˜ค ์†Œ๋…„. ๊ณต์‹์ ์ธ ์ˆ˜์ •์ด ์ง„ํ–‰ ์ค‘์ผ๊นŒ์š”?

๋‚˜๋Š” RN 0.62.1์„ ์‚ฌ์šฉ ํ•˜๊ณ 

doLast ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋“œ๋กœ์–ด ๋ธ” ํด๋” ๋ฅผ

๊ณต์‹ ์ถ”์ฒœ์ด ๋ฌด์—‡์ธ์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

์œ ์ง€ํ•ด์•ผํ•˜๋Š” ๋“œ๋กœ์–ด ๋ธ” ๋ฆฌ์†Œ์Šค๊ฐ€ ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋“œ๋กœ์–ด ๋ธ” ํด๋”๋ฅผ ์ œ๊ฑฐํ•˜๋ฉด ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด ๋ฌธ์ œ๋Š” android/app/src/main/res/raw ํด๋”์˜ ๋ชจ๋“  ํ•ญ๋ชฉ๊ณผ android/app/src/main/res/drawable ํด๋”์˜ nodemodules... ๋กœ ์‹œ์ž‘ํ•˜๋Š” ํŒŒ์ผ์— ๋Œ€ํ•œ duplicate resources ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

android/app/build.gradle :

...
project.ext.react = [
    ...
    bundleInRelease        : true,
    resourcesDirRelease   : "src/release/res",
    ...
]
...

node ์—์„œ android/app/src/main/drawable* node ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ชจ๋“  ํ•ญ๋ชฉ ์ œ๊ฑฐ :

rm android/app/src/main/drawable*/node*
rm -rf android/app/src/main/raw

ํ”„๋กœ์ ํŠธ๋ฅผ ์ •๋ฆฌํ•˜๊ณ  ๋ฐ˜์‘ ํ˜• ๊ธฐ๋ณธ ๋ฒˆ๋“ค ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์ง€ ๋ง๊ณ  ๋‹ค์‹œ ๋นŒ๋“œํ•˜์‹ญ์‹œ์˜ค.

์ด๊ฒƒ์ด ๋ˆ„๊ตฐ๊ฐ€๋ฅผ ๋•๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค!

์œ„์˜ ์†”๋ฃจ์…˜์€ ์ ์ ˆํ•œ ๋Œ€๋‹ต์„ ์ฐพ๋Š” ๋ฐ ๋„์›€์ด๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

1 ๋‹จ๊ณ„:

android/app/build.gradle :

... project.ext.react = [ ... bundleInRelease : true, resourcesDirRelease : "src/release/res", ... ] ...

2 ๋‹จ๊ณ„:

๋‹ค์Œ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ ๋ชจ๋“  node_module ํŒŒ์ผ์„ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.

rm -rf drawable*/node*

3 ๋‹จ๊ณ„ :

์ด ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ๋นŒ๋“œํ•˜๊ณ  APK๋ฅผ ๋งŒ๋“œ์„ธ์š”.

./gradlew assembleRelease

4 ๋‹จ๊ณ„ :

๋‚ด package.json์—์„œ ์‚ฌ์šฉํ•  ๋‹ค์Œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

"release-apk": "cd android && yarn remove-duplicate-files  && ./gradlew assembleRelease"

๋„์›€์ด ๋˜์—ˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค!
๊ทธ๋ฆฌ๊ณ  ํ•ด๊ฒฐ์ฑ…์„ ์ œ์‹œํ•ด ์ฃผ์‹  ๋ชจ๋“  ๋ถ„๋“ค๊ป˜ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์ด๋ฏธ์ง€๊ฐ€ ์•„๋‹Œ ์›์‹œ ๋ฆฌ์†Œ์Šค์— ๋ฌธ์ œ๊ฐ€์žˆ๋Š” ์‚ฌ๋žŒ ์ด๋ฆ„์€ ๊ฐ™์ง€๋งŒ ํ™•์žฅ์ž๊ฐ€ ๋‹ค๋ฅธ ํŒŒ์ผ์˜ ์ด๋ฆ„ ์„ .

๋‚ด ๊ฒฝ์šฐ

object.obj ๋ฐ object.mtl ํŒŒ์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ™•์žฅ์ž๊ฐ€ ๋‹ค๋ฅด๋”๋ผ๋„ ์ค‘๋ณต ์ž์› ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์•ˆ๋“œ๋กœ์ด๋“œ๋Š” ํŒŒ์ผ ์ด๋ฆ„์œผ๋กœ ๊ทธ๋“ค์„ ์„ ํƒํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ, ์ด๋ฆ„ ๋ณ€๊ฒฝ object.mtl ์— object_material.mtl ๊ฒฐ๊ตญ ๋‚˜๋ฅผ ์œ„ํ•ด ๊ทธ๊ฒƒ์„ ํ•ด๊ฒฐํ–ˆ๋‹ค.

์ด๋ฏธ์ง€ ๋ฆฌ์†Œ์Šค์˜ ๊ฒฝ์šฐ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋™์ผํ•œ ์ด๋ฆ„์˜ ์ด๋ฏธ์ง€๊ฐ€์žˆ๋Š” ๊ฒฝ์šฐ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•ด๋ณด์„ธ์š”.

๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ•œ ๊ฒƒ์€ ๋‘ ๊ฐ€์ง€ ์˜๊ฒฌ์˜ ์กฐํ•ฉ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋„๋ก ์—ฌ๊ธฐ์— ๋ถ™์—ฌ ๋„ฃ์Šต๋‹ˆ๋‹ค.

def flavorPathSegment = ""
android.productFlavors.all { flavor ->
if (targetName.toLowerCase().contains(flavor.name)) {
                    flavorPathSegment = flavor.name
            }
            }

            doLast {
                def moveFunc = { resSuffix ->
                    File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/drawable-${resSuffix}")
                    if (originalDir.exists()) {
                        File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}")
                        ant.move(file: originalDir, tofile: destDir)
                    }
                }
                def moveRawFunc = { dir ->
                    File originalDir = file("$buildDir/generated/res/react/${flavorPathSegment}release/${dir}")
                    if (originalDir.exists()) {
                        File destDir = file("$buildDir/../src/main/res/${dir}")
                        ant.move(file: originalDir, tofile: destDir)
                    }
                }

                moveFunc.curry("ldpi").call()
                moveFunc.curry("mdpi").call()
                moveFunc.curry("hdpi").call()
                moveFunc.curry("xhdpi").call()
                moveFunc.curry("xxhdpi").call()
                moveFunc.curry("xxxhdpi").call()
                moveRawFunc.curry("raw").call()
            }

targetName.toLowerCase().contains(flavor.name.toLowerCase()) ์ผํ•ฉ๋‹ˆ๋‹ค.
๋‚ด flavor.name ๋Š” xxXX์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

๋ชจ๋“  dolast ํ•ญ๋ชฉ์€ PR # 24518 ๋ฐ # 24778์— ์ถ”๊ฐ€ ๋œ ๋‹ค์Œ # 25363์—์„œ ๋‹ค์‹œ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ œ๊ฑฐ ๋œ ์ด์œ ๋ฅผ ์•„๋Š” ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ด๊ฒƒ์€ ์˜ค๋žซ๋™์•ˆ ์ง€์†๋˜๋Š” ๋ฌธ์ œ์˜€์œผ๋ฉฐ ๊ทธ๋“ค์ด ํ•ด๊ฒฐํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

์‹ ๊ฒฝ ์“ฐ์ง€ ๋งˆ์„ธ์š”.
https://github.com/facebook/react-native/issues/22234#issuecomment -504721069
๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ : https://github.com/facebook/react-native/issues/25325

๋„์›€์ด๋˜๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ์€ ๋‚ด ์Šคํฌ๋ฆฝํŠธ์—์„œ ํ•œ ์ค„๋กœ ๋œ ๋ช‡ ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค (Android X ๋ฌธ์ œ๋„ ํ•ด๋‹น).

echo "Fixing java error: package android.support.v4.widget does not exist issue with Android X"

npm install jetifier
npx jetify

echo "Fixing duplicate resources issue"
rm -rf .../android/app/src/main/res/raw

cd .../node_modules/react-native

cat <<EOT >> react_gradle.patch
121a122,137
>             doLast {
>                 def moveFunc = { resSuffix ->
>                     File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");
>                     if (originalDir.exists()) {
>                         File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
>                         ant.move(file: originalDir, tofile: destDir);
>                     }
>                 }
>                 moveFunc.curry("ldpi").call()
>                 moveFunc.curry("mdpi").call()
>                 moveFunc.curry("hdpi").call()
>                 moveFunc.curry("xhdpi").call()
>                 moveFunc.curry("xxhdpi").call()
>                 moveFunc.curry("xxxhdpi").call()
>             }
> 
EOT

ls -l react_gradle.patch
patch react.gradle react_gradle.patch

์ด ์†”๋ฃจ์…˜์€ ๋ฆด๋ฆฌ์Šค ๋นŒ๋“œ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ๋„์›€์ด๋˜์—ˆ์Šต๋‹ˆ๋‹ค : https://github.com/facebook/react-native/issues/26245#issuecomment -631382817

๋‹ค์Œ ๋‹จ๊ณ„๋Š” ๋‚˜๋ฅผ ์œ„ํ•ด ๊ทธ๊ฒƒ์„ํ–ˆ์Šต๋‹ˆ๋‹ค.

1. gradlew clean
2. npm install
3. gradlew bundleRelease
System:
    OS: macOS 10.15.3
    CPU: (4) x64 Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz
    Memory: 221.64 MB / 8.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 12.13.1 - ~/.nvm/versions/node/v12.13.1/bin/node
    Yarn: 1.22.4 - ~/Documents/youpendo-app-bareworkflow/node_modules/.bin/yarn
    npm: 6.12.1 - ~/.nvm/versions/node/v12.13.1/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.9.3 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1
    Android SDK:
      API Levels: 28, 29
      Build Tools: 28.0.3, 29.0.2
      System Images: android-28 | Google APIs Intel x86 Atom, android-29 | Google APIs Intel x86 Atom
      Android NDK: Not Found
  IDEs:
    Android Studio: 3.6 AI-192.7142.36.36.6392135
    Xcode: 11.3.1/11C504 - /usr/bin/xcodebuild
  Languages:
    Java: 1.8.0_232 - /usr/bin/javac
    Python: 2.7.16 - /usr/bin/python
  npmPackages:
    @react-native-community/cli: ^4.8.0 => 4.10.0
    react: 16.11.0 => 16.11.0
    react-native: 0.62.2 => 0.62.2
  npmGlobalPackages:
    *react-native*: Not Found

๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ํ•ด๊ฒฐ์ฑ…?

๋ˆ„๊ตฐ๊ฐ€ ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ 0.62.2์— ๋Œ€ํ•œ ํŒจ์น˜ ํŒŒ์ผ์„ ๊ณต์œ ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

React Native 0.63.2 ์šฉ์œผ๋กœ์ด ํŒจ์น˜๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. 'drawable- ' ํด๋”๊ฐ€์žˆ๋Š” ๊ฒฝ์šฐ 'mipmap-'์œผ๋กœ ์ด๋ฆ„์„ ๋ฐ”๊พธ๊ณ  android / app / src / main / AndroidManifest.xml ์—์„œ ์ฐธ์กฐ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ์˜ ๋ฃจํŠธ์—์„œ ์ด๊ฒƒ์„ ์‹คํ–‰ํ•˜์—ฌ ํŒจ์น˜ ํŒŒ์ผ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

cat <<EOT >> react-native-0.63.2-react.gradle.patch 
@@ -147,6 +147,23 @@
                 jsSourceMapsDir.mkdirs()
             }

+            doLast {
+                def moveFunc = { resFolder ->
+                    File originalDir = file("\${buildDir}/generated/res/react/release/\${resFolder}");
+                    if (originalDir.exists()) {
+                        File destDir = file("\${buildDir}/../src/main/res/\${resFolder}");
+                        ant.move(file: originalDir, tofile: destDir);
+                    }
+                }
+                moveFunc.curry("drawable-ldpi").call()
+                moveFunc.curry("drawable-mdpi").call()
+                moveFunc.curry("drawable-hdpi").call()
+                moveFunc.curry("drawable-xhdpi").call()
+                moveFunc.curry("drawable-xxhdpi").call()
+                moveFunc.curry("drawable-xxxhdpi").call()
+                moveFunc.curry("raw").call()
+            }
+
             // Set up inputs and outputs so gradle can cache the result
             inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
             outputs.dir(jsBundleDir)
EOT

๊ทธ๋Ÿฐ ๋‹ค์Œ ํŒจ์น˜๋ฅผ

patch node_modules/react-native/react.gradle < react-native-0.63.2-react.gradle.patch

๋˜ํ•œ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค

rm -Rf android/.gradle
cd android && gradlew clean

node_ modules/react-native/react.gradle ์„ android/app/react.gradle ๋ณต์‚ฌ ํ•œ ๋‹ค์Œ android/app/build.gradle ๋ฐ android/app/react.gradle :

android/app/build.gradle

- apply from: "../../node_modules/react-native/react.gradle"
+ apply from: "./react.gradle"

android/app/react.gradle

           doFirst {
                jsBundleDir.deleteDir()
                jsBundleDir.mkdirs()
                resourcesDir.deleteDir()
                resourcesDir.mkdirs()
                jsIntermediateSourceMapsDir.deleteDir()
                jsIntermediateSourceMapsDir.mkdirs()
                jsSourceMapsDir.deleteDir()
                jsSourceMapsDir.mkdirs()
            }
+
+           doLast {
+               def moveFunc = { resSuffix ->
+                   File originalDir = file("${resourcesDir}/drawable-${resSuffix}")
+                   if (originalDir.exists()) {
+                      File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}")
+                       ant.move(file: originalDir, tofile: destDir)
+                   }
+               }
+               def moveRawFunc = { dir ->
+                  File originalDir = file("${resourcesDir}/${dir}")
+                  if (originalDir.exists()) {
+                      File destDir = file("$buildDir/../src/main/res/${dir}")
+                      ant.move(file: originalDir, tofile: destDir)
+                  }
+              }
+
+              moveFunc.curry("ldpi").call()
+              moveFunc.curry("mdpi").call()
+              moveFunc.curry("hdpi").call()
+              moveFunc.curry("xhdpi").call()
+              moveFunc.curry("xxhdpi").call()
+              moveFunc.curry("xxxhdpi").call()
+              moveRawFunc.curry("raw").call()
+          }

์ด๊ฒƒ์€ react-native 0.63.2 ์—์„œ ์ €์—๊ฒŒ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.

            doLast {
                def flavorPathSegment = ""
                println targetName.toLowerCase();
                android.productFlavors.all { flavor ->
                    if (targetName.toLowerCase().contains(flavor.name.toLowerCase())) {
                        flavorPathSegment = flavor.name
                    }
                }
                def moveFunc = { resFolder ->
                    File originalDir = file("${buildDir}/generated/res/react/${flavorPathSegment}/release/${resFolder}");
                    if (originalDir.exists()) {
                        File destDir = file("${buildDir}/../src/main/res/${resFolder}");
                        ant.move(file: originalDir, tofile: destDir);
                    }
                }

                moveFunc.curry("drawable").call()
                moveFunc.curry("drawable-ldpi").call()
                moveFunc.curry("drawable-mdpi").call()
                moveFunc.curry("drawable-hdpi").call()
                moveFunc.curry("drawable-xhdpi").call()
                moveFunc.curry("drawable-xxhdpi").call()
                moveFunc.curry("drawable-xxxhdpi").call()
                moveFunc.curry("raw").call()
            }


์—ฌ๊ธฐ์— ํŒจ์น˜ ํŒŒ์ผ react-native+0.63.2.patch

diff --git a/node_modules/react-native/react.gradle b/node_modules/react-native/react.gradle
index 6441d93..1eb4645 100644
--- a/node_modules/react-native/react.gradle
+++ b/node_modules/react-native/react.gradle
@@ -147,6 +147,33 @@ afterEvaluate {
                 jsSourceMapsDir.mkdirs()
             }

+            doLast {
+                def flavorPathSegment = ""
+                println targetName.toLowerCase();
+                android.productFlavors.all { flavor ->
+                    if (targetName.toLowerCase().contains(flavor.name.toLowerCase())) {
+                        flavorPathSegment = flavor.name
+                    }
+                }
+                def moveFunc = { resFolder ->
+                    File originalDir = file("${buildDir}/generated/res/react/${flavorPathSegment}/release/${resFolder}");
+                    if (originalDir.exists()) {
+                        File destDir = file("${buildDir}/../src/main/res/${resFolder}");
+                        ant.move(file: originalDir, tofile: destDir);
+                    }
+                }
+
+                moveFunc.curry("drawable").call()
+                moveFunc.curry("drawable-ldpi").call()
+                moveFunc.curry("drawable-mdpi").call()
+                moveFunc.curry("drawable-hdpi").call()
+                moveFunc.curry("drawable-xhdpi").call()
+                moveFunc.curry("drawable-xxhdpi").call()
+                moveFunc.curry("drawable-xxxhdpi").call()
+                moveFunc.curry("raw").call()
+            }
+
+
             // Set up inputs and outputs so gradle can cache the result
             inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
             outputs.dir(jsBundleDir)
diff --git a/node_modules/react-native/scripts/.packager.env b/node_modules/react-native/scripts/.packager.env
new file mode 100644
index 0000000..21a13cf
--- /dev/null
+++ b/node_modules/react-native/scripts/.packager.env
@@ -0,0 +1 @@
+export RCT_METRO_PORT=8081
\ No newline at end of file

์•ˆ๋…•ํ•˜์„ธ์š”! ๋ˆ„๊ตฐ๊ฐ€ ์ด๋Ÿฌํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋Œ€ํ•ด PR์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? node_modules ํŽธ์ง‘์€ ์ด์ƒ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š”,

๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ 0.63.2๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋˜ํ•œ์ด ๋ฌธ์ œ์— ์ง๋ฉดํ•˜๊ณ  react.gradle ํŽธ์ง‘, ๋ฆฌ์†Œ์Šค / ๋“œ๋กœ์–ด ๋ธ” ์‚ญ์ œ ๋“ฑ์„ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋งˆ์นจ๋‚ด gradlew assembleRelease ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ฉด ์ €์—๊ฒŒ ํšจ๊ณผ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

react-native bundle ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. gradlew assembleRelease ๋Š” react-native ๋ฒˆ๋“ค์„ ์‹คํ–‰ํ•˜๊ณ  apk ์ž์ฒด๋ฅผ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ react-native 0.63.2 ์—์„œ ์ €์—๊ฒŒ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.

            doLast {
                def flavorPathSegment = ""
                println targetName.toLowerCase();
                android.productFlavors.all { flavor ->
                    if (targetName.toLowerCase().contains(flavor.name.toLowerCase())) {
                        flavorPathSegment = flavor.name
                    }
                }
                def moveFunc = { resFolder ->
                    File originalDir = file("${buildDir}/generated/res/react/${flavorPathSegment}/release/${resFolder}");
                    if (originalDir.exists()) {
                        File destDir = file("${buildDir}/../src/main/res/${resFolder}");
                        ant.move(file: originalDir, tofile: destDir);
                    }
                }

                moveFunc.curry("drawable").call()
                moveFunc.curry("drawable-ldpi").call()
                moveFunc.curry("drawable-mdpi").call()
                moveFunc.curry("drawable-hdpi").call()
                moveFunc.curry("drawable-xhdpi").call()
                moveFunc.curry("drawable-xxhdpi").call()
                moveFunc.curry("drawable-xxxhdpi").call()
                moveFunc.curry("raw").call()
            }

์—ฌ๊ธฐ์— ํŒจ์น˜ ํŒŒ์ผ react-native+0.63.2.patch

diff --git a/node_modules/react-native/react.gradle b/node_modules/react-native/react.gradle
index 6441d93..1eb4645 100644
--- a/node_modules/react-native/react.gradle
+++ b/node_modules/react-native/react.gradle
@@ -147,6 +147,33 @@ afterEvaluate {
                 jsSourceMapsDir.mkdirs()
             }

+            doLast {
+                def flavorPathSegment = ""
+                println targetName.toLowerCase();
+                android.productFlavors.all { flavor ->
+                    if (targetName.toLowerCase().contains(flavor.name.toLowerCase())) {
+                        flavorPathSegment = flavor.name
+                    }
+                }
+                def moveFunc = { resFolder ->
+                    File originalDir = file("${buildDir}/generated/res/react/${flavorPathSegment}/release/${resFolder}");
+                    if (originalDir.exists()) {
+                        File destDir = file("${buildDir}/../src/main/res/${resFolder}");
+                        ant.move(file: originalDir, tofile: destDir);
+                    }
+                }
+
+                moveFunc.curry("drawable").call()
+                moveFunc.curry("drawable-ldpi").call()
+                moveFunc.curry("drawable-mdpi").call()
+                moveFunc.curry("drawable-hdpi").call()
+                moveFunc.curry("drawable-xhdpi").call()
+                moveFunc.curry("drawable-xxhdpi").call()
+                moveFunc.curry("drawable-xxxhdpi").call()
+                moveFunc.curry("raw").call()
+            }
+
+
             // Set up inputs and outputs so gradle can cache the result
             inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
             outputs.dir(jsBundleDir)
diff --git a/node_modules/react-native/scripts/.packager.env b/node_modules/react-native/scripts/.packager.env
new file mode 100644
index 0000000..21a13cf
--- /dev/null
+++ b/node_modules/react-native/scripts/.packager.env
@@ -0,0 +1 @@
+export RCT_METRO_PORT=8081
\ No newline at end of file

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰