반응형

 

https://swiperjs.com/demos

 

Swiper Demos

Swiper is the most modern free mobile touch slider with hardware accelerated transitions and amazing native behavior.

swiperjs.com

 

반응형
반응형

브라우저에서 모바일 애플리케이션 열기. 

Open Mobile Application From The Browser( web) , intent, deeplink, url scheme

https://vhudyma-blog.eu/open-mobile-application-from-the-browser/  

 

딥링킹 유형

딥 링크에는 두 가지 주요 유형이 있습니다.

  • 기본
  • 링크는 응용 프로그램이 설치되어 있으면 열리고 그렇지 않으면 오류 메시지가 표시됩니다.
  • 연기
  • 링크는 애플리케이션이 설치되어 있으면 열리고, 그렇지 않으면 사용자가 Play 또는 App Store(또는 선택한 다른 위치)로 리디렉션됩니다.

이 외에도 Contextual Deep Linking 에 대해 들어보셨을 것입니다 .

상황별 딥 링크는 일반적으로 사용자에 대한 추가 정보를 수집하기 위해 추가된 일부 추가 매개변수와 함께 기본이거나 지연됩니다.


 

웹 브라우저에서 앱 열기

 

URL Scheme

사용자를 앱의 특정 콘텐츠로 바로 연결하는 URL 이다.

ex) naversearchapp://

위와 같은 URL Scheme를 이용하면 브라우저에서 해당 Scheme를 읽고 그 Scheme에 해당하는 앱이 있는 경우 (앱에서 설정) 열어준다.

하지만 다음과 같은 한계가 있다.

  • naversearchapp 같이 앞에 붙는 스키마는 유니크한 값이 아니기 때문에 같은 이름이 있을 경우 어떤앱을 열지 물어보게된다.
  • 앱이 미설치되어있는 경우 동작하지 않는다.

Android

intent filter

https://developer.android.com/guide/components/intents-filters?hl=ko

이 intent filter의 역할은 앱 열기에 한정된 것이 아니고 특정 앱으로의 메시징을 처리하는 객체인데, 이걸 딥링크처럼 활용할 수 있다.

앱에서 intent관련 설정을 지정하고, 웹에서 intent:// 와 같이 실행하면 앱을 실행할 수 있다.

이 방법은 위 URL 스키마 방식의 한계를 없애준다.

패키지명을 이용하기 때문에 유니크하고, 앱이 미설치되어있는 경우 해당 패키지에 해당되는 playstore로 이동한다.

https://developer.android.com/training/app-links/verify-site-associations?hl=ko

위 인텐트 필터 방식을 활용하여 웹사이트 URL 기반으로 앱을 여는 방식 (android 6.0 이상지원)

예를들어 https://medium.com 를 방문하는 경우 해당하는 앱을 열 수 있다.

웹에서는 무엇을 해주어야 하나?

기본적으로 인텐트 필터 설정은 앱쪽에서 해주지만, 웹에서도 해줘야할 것이 있다.

앱링크를 제공할 도메인이 특정 앱과 매칭된다는 것을 알려주기 위해 앱쪽에서 생성하는 assetlinks.json  https://{도메인}/.well-known/assetlinks.json 에 제공해줘야한다.

여기에는 몇 가지 제약이 따르게 되는데,

  1. HTTPS만 지원한다.
  2. assetlinks.json 를 가져오는데에 있어서 리디렉션이 일어나지 않아야하고 application/json 타입으로 응답되어야한다.
  3. 서브도메인이 다른 경우 모두 assetlinks.json 제공이 필요하다. 예를들어 www.medium.com  m.medium.com 가 존재한다면, assetlinks.json 를 모두 제공해야한다.
  4. robot.txt 가 접근가능해야한다. 즉, VPN 등이 있어야 접근가능한 경우 적용 불가능하다.

테스트는 어떻게하지?

이부분이 제일 골치아팠는데, 위와 같은 제약사항이 있기 때문에 VPN을 사용하거나 사내망이 따로 있는 경우 테스트하기가 번거롭다.

예를들어, 개발환경인 dev.aa.com 가 있고, 실제환경인 aa.com 이 있다고 했을 때 위 제약사항이 있기 때문에 assetlinks.json을 두 환경을 제공하는 서버 각각 넣어줘야한다.

대부분에 개발환경 서버는 VPN 뒤에 있기 때문에 위 4번 제약사항에 걸리게 된다.

이 때 찾아보았던 해결할 수 있는 방법은

  1. 만약 dev.aa.com  aa.com 과 같이 서브도메인 / 루트도메인의 관계라면 루트도메인에 assetlinks를 *.aa.com 과같이 설정함으로써 적용이 가능하다.
  2. app.dev.aa.com 과 같은 서버를 실제환경에 열어두고 여기서 테스트를 진행한다.

앱이 설치되어있지 않은 경우는?

기본적으로 앱링크 / 유니버셜링크는 앱이 설치되어있지 않은 경우 단순히 웹에서 해당 url을 표시하게 된다. 이런 경우 보통 "앱으로 이동" 과 같은 버튼을 표시하고, 클릭시 위에서 말한 인텐트 필터를 사용하게 된다.

iOS

ios의 경우 deffered deep link나 intent 필터 등의 기법은 없고 universal 링크만 이용 가능하다. (ios 9 이상)

https://developer.apple.com/ios/universal-links/

기본적으로 app link와 동일하다. 웹사이트 URL 기반으로 앱을 열게 동작해준다.

웹에서는 무엇을 해주어야 하나?

안드로이드와 마찬가지로 .well-known 하위에 파일 추가가 필요하다. (다른점은 루트 디렉토리에 넣어도 무방)

앱쪽에서 생성한 apple-app-site-association 파일을 넣어주게되는데, 마찬가지로 application/json 타입 제공이 필요하다.

주의할 점은, 안드로이드의 경우 assetlinks.json 의 파일 포맷이 json 이라 브라우저가 알아서 json 으로 처리해주는 반면, 해당 파일은 파일 포맷이 없으므로, 명시적으로 제공이 필요하다.

기본적인 제약사항 (VPN X, redirect X, 서브도메인지원 X)은 앱링크와 동일하다.

따로 문서에 명시되어있지는 않은데, 테스트 결과 앱링크와 마찬가지로 앱쪽에서 *.루트도메인 과 같이 설정한 경우 루트도메인에 넣은 설정파일로 서브도메인 지원이 가능하다.

앱이 설치되어있지 않은 경우는?

마찬가지로 앱열기버튼을 제공할 수 있다. (특히 유니버셜링크는 safari의 경우 앱열기버튼을 네이티브에서 제공하고 있다)

다만, iOS에서는 인텐트 필터처럼 앱의 설치여부를 구분해서 동작할 수 없기 때문에 조금 추가작업이 필요하다.

다음과 같은 방법을 고려할 수 있다.

  • firebase 다이나믹링크, 브랜치 등 외부 서비스를 이용하는 방식 (ex ) Medium, reddit )
    • 위 서비스들이 앱 설치/미설치시 분기처리를 제공해준다. Android의 경우 내부적으로 인텐트 필터를 이용하는 것으로 보인다.
  • 직접 처리하는 방식
    • 라우트를 https://aa.com/launchApp 과 같이 지정해놓고, 해당 라우트로 리디렉션 시킨다.
    • 만약 앱이 설치되어 있다면 유니버셜링크를 통해 서버에 접근하지않고 바로 앱이 열릴테고, 앱이 설치되어있지 않다면 해당 라우트로 들어오고 fe 서버에서 app store로 리디렉션 시킬 수 있다.

 

* https://godsenal.com/posts/%EC%9B%B9-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%97%90%EC%84%9C-%EC%95%B1-%EC%97%B4%EA%B8%B0/

반응형
반응형
UI 애니메이션 기획에 영감을 주는 “30가지 애니메이션 샘플”을 정리한 블로그 글입니다.

#Developer #개발자 #기발자 #Animation #애니메이션 #Transition #트랜지션 #UI #iOS

UI 애니메이션 기획에 영감을 주는 “30가지 애니메이션 샘플”을 정리한 블로그 글입니다.

반응형
반응형
반응형
반응형
Customizing Ionic Apps for Web & Mobile

https://blog.ionicframework.com/customizing-ionic-apps-for-web-mobile/

Toggle navigation

FrameworkProductsShowcaseBlogDocsSupport Getting StartedCommunity ForumCustomer SupportTrusted PartnersEcosystem MarketJobsShopCreatorTwitterSlackGitHubLog inSign up

Customizing Ionic Apps for Web & Mobile

By Simon on February 12, 2018DESKTOPFRAMEWORKTUTORIALS

This is a guest post from Simon Grimm, speaker and educator at Ionic Academy. Simon writes about Ionic frequently on his blog Devdactic.

With the development of Ionic apps comes the promise that your code will run on various platforms and screen sizes once it’s ready. While this can work and look fine on your targeted devices out of the box, it might not at first for everyone.

In this post, we’ll take a look at 4 areas to keep an eye on – especially if you plan to ship your Ionic app both as a website (or perhaps PWA?) and also as a native mobile app (perhaps even on phone and tablet devices).

Everything we need is already built into Ionic, but sometimes it’s easy to forget about all the awesomeness. So let’s get started with a tiny base for our examples!

App Starting Template Setup

For this article run the command below to start a new Ionic app with the side menu template:

ionic start devdacticResponsive sideMenu

It’s a super basic app with just 2 pages and a side menu (otherwise the name would be kinda bad) but we also need to make HTTP calls, therefore we use the new HttpClient which is available since Angular 5 and Ionic 3.9.0.

Simply change your app/app.module.ts to:

import { BrowserModule } from '@angular/platform-browser'; import { ErrorHandler, NgModule } from '@angular/core'; import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular'; import { MyApp } from './app.component'; import { HomePage } from '../pages/home/home'; import { ListPage } from '../pages/list/list'; import { StatusBar } from '@ionic-native/status-bar'; import { SplashScreen } from '@ionic-native/splash-screen'; import { HttpClientModule } from '@angular/common/http'; @NgModule({ declarations: [ MyApp, HomePage, ListPage ], imports: [ BrowserModule, IonicModule.forRoot(MyApp), HttpClientModule ], bootstrap: [IonicApp], entryComponents: [ MyApp, HomePage, ListPage ], providers: [ StatusBar, SplashScreen, {provide: ErrorHandler, useClass: IonicErrorHandler} ] }) export class AppModule {}

That’s all we’ll need for our examples, so now let’s dive into our areas.

1. Responsive Grid Layout

Most Ionic components already adapt to screen changes and look good across various sizes. However, having something like a list item full size or an Ionic Card displayed full width on my large iMac screen kills my eyes. 

If you need your app to look good on a small device and in a desktop web browser, you’ll need to make it as responsive as possible. And what’s better then using the Ionic Grid layout system?

But first we need some data we can display inside a list, so let’s add a simple HTTP call to your pages/home/home.ts like this:

import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; import { Observable } from 'rxjs/Observable'; import { HttpClient } from '@angular/common/http'; import "rxjs/add/operator/map"; @Component({ selector: 'page-home', templateUrl: 'home.html' }) export class HomePage { users: Observable<any>; constructor(public navCtrl: NavController, private httpClient: HttpClient, private plt: Platform, private alertCtrl: AlertController) { this.users = this.httpClient.get('https://randomuser.me/api/?results=20') .map(res => res['results']) } }

Now we have an array of users from the Randomuser API which we can display as cards. You could make this as simple iteration without any further testing, but if you’re serious about your design (which, of course you are!), you’ll want to make sure to test different sizes and breakpoints.

A breakpoint is a predefined value at which your design snaps from one category to the next. If your screen is smaller than 576px, you fall into the smallest category which is xs. However, at 577px your design will get the sm category applied, so you must prepare your design to also look good there, and at later breakpoints as well.

With Ionic, we can use the row and column system plus the breakpoints to build interfaces that look great across different platforms and adapt to display the best and most intuitive interface to the user.

Let’s take our example and add this code to our pages/home/home.html:

<ion-header> <ion-navbar> <button ion-button menuToggle> <ion-icon name="menu"></ion-icon> </button> <ion-title>Home</ion-title> </ion-navbar> </ion-header> <ion-content> <ion-grid> <ion-row> <ion-col *ngFor="let user of users | async" col-12 col-xl-2 col-lg-3 col-md-4> <ion-card> <ion-item> <ion-avatar item-start> <img [src]="user.picture.medium"> </ion-avatar> <h2 text-capitalize>{{ user.name?.first }} {{ user.name?.last }}</h2> </ion-item> <ion-card-content> Bacon ipsum dolor amet salami prosciutto ham hock, strip steak buffalo ribeye pork chop. Beef ribs tenderloin tail shoulder. Spare ribs ham shoulder brisket rump hamburger. Pork belly kevin shoulder prosciutto ribeye pork chop chicken strip steak pig. </ion-card-content> </ion-card> </ion-col> </ion-row> </ion-grid> </ion-content>

One Ionic row offers 12 units space for columns, so each column can take an amount of those 12. If your row takes 12 units, it means the row is already full and the next column will be displayed in the following row.

The syntax for the column isn’t immediately obvious, so let’s dive deeper into what it actually means:

col-12: If no other rules match, the column will take all 12 units (greedy column!)col-md-4: At a minimum width of 768px, each column will only use 4 units. This means, a row can now handle 3 columnscol-lg-3: As the screen gets bigger than 992px, a column only needs 3 units which means the row how holds 4 columnscol-xl-2: On the largest screens (1200px+), a column only needs 2 units and a row will display 6 columns

In our example, a column always holds a card, so the design ranges from seeing only 1 card to 6 cards maximum (seen below).

Using a decent flexible layout is definitely mandatory if your app is going to run on multiple platforms and screen sizes. If you don’t invest time into doing this, your app might scare off potential users because it just looks odd.

There’s a lot more to the Grid like setting your own breakpoints, reordering columns, and more so go check it out!

2. CSS Media Queries

While we can’t really accredit this one directly to Ionic, we are still lucky that Ionic bets strongly on the Web and we can thus take advantage of languages like CSS, which most of us have all learned years ago.

Just like the grid layout, we can make use of breakpoints here as well by using @media and different sizes to change part of our UI.

In a recent app, we needed an ion-fabbutton at the top right corner on the web version as it was too hard to spot when it was at the far bottom right corner. However, on a mobile version of your app users are already familiar with having the button floating above lists at the bottom right.

This means the element needs exist in completely different places depending on screen size (and this is a simple element).

One way to achieve this is by having the element there twice, but only displaying it when the media query of your CSS matches. To do this, add the Fab button to your your pages/home/home.html after the list we already have:

<ion-fab right bottom class="web-fab"> <button ion-fab icon-only color="primary" (click)="checkPlatform()"> <ion-icon name="help"></ion-icon> </button> </ion-fab> <ion-fab right top edge class="mobile-fab"> <button ion-fab icon-only color="primary" (click)="checkPlatform()"> <ion-icon name="help"></ion-icon> </button> </ion-fab>

If you want to make only one button visible, you could use the follow CSS inside your pages/home/home.scss:

page-home { @media (max-width: 576px) { ion-card-content { font-size: 2rem !important; } } @media (max-width: 820px) { .mobile-fab { display: none; } } @media (min-width: 820px) { .web-fab {


. . .
반응형
반응형


Slide : http://seoul.reactjs.kr/assets/slides/react_native.pdf



...

반응형
반응형

Realm은 어떻게 효율적인
 데이터베이스를 만들었나?

https://deview.kr/2017/schedule/206


Realm은 SQLite만 사용되던 모바일 데이터베이스 시장에서 혁신적인 대안으로 평가받고있는 오픈소스 데이터베이스 입니다. 현재 10만명 이상의 개발자들이 개발에 사용하고있고, 20억대 이상의 디바이스에 설치되어 있습니다. 


Realm을 빠르고 효율적인 데이터베이스로 만들기 위해 사용되었던 여러 기술과 고려되었던 여러 사안들이 있습니다. Realm이 이슈들을 어떤 방법으로 대처해왔는지를 살피고 거기에서 응용과 프레임워크 개발에서 얻을 수 있는 교훈을 살펴봅시다.




how can realm_make_efficient_mobile_database

1. Realm은 어떻게 효율적인 데이터베이스를 만들었나? Leonardo YongUk Kim Java team

2. GreenDao ORMLite SQLite Realm

3. 첫번째 비결 Zero copy

4. Zero copy “최대한 복제를 미루는 것입니 다.”

5. 왜 Zero copy인가? 

public class City { private String name; private long votes; 

public String getName() { return name; } 

public void setName(String name) { this.name = name; } 

public long getVotes() { return votes; } 

public void setVotes(long votes) { this.votes = votes; } } 

제로 카피 없는 세상을 생각해 봅시다.

6. 왜 Zero copy인가? 

public class City { 

private String name; private long votes; 

public String getName() { return name; } 

public void setName(String name) { this.name = name; } 

public long getVotes() { return votes; } 

public void setVotes(long votes) { this.votes = votes; }

 }

ORM이나 JSON 파서가 채워줘야 해요. 

ORM이나 JSON 파서가 채워줘야 해요.

7. 왜 Zero copy인가? public class City { private String name; private long votes; public String getName() { return name; } public void setName(String name) { this.name = name; } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } public List<City> hydrate() { List<City> results = new ArrayList<>(); while (hasNextItem) { City c = new City(); c.setName(name); c.setVotes(votes); results.add(c); } return results; } 너가 뭘 쓸지 몰라서 다 준비했어요.

8. 왜 Zero copy인가? public List<City> hydrate() { List<City> results = new ArrayList<>(); while (hasNextItem) { City c = new City(); c.setName(name); c.setVotes(votes); /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ results.add(c); } return results; } 너가 뭘 쓸지 몰라서 다 준비했어요. 수화라고 번역합니다. 객체의 필드를 채우는 일입니다.

9. 왜 Zero copy인가? public List<City> hydrate() { List<City> results = new ArrayList<>(); while (hasNextItem) { City c = new City(); c.setName(String.valueOf(name)); c.setVotes(Integer.parseInt(votes)); /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ results.add(c); } return results; } 어쩌면 매번 변환이 필요할지 몰라Yo~!

10. 왜 Zero copy인가? public class City { private String name; private long votes; public String getName() { return name; } public void setName(String name) { this.name = name; } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } 만약에 사용자가 getName만 필요하면? votes값의 변환과 설정은 필요없는 것 아닌가?

11. 왜 Zero copy인가? public class City { private String name; private long votes; private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } row에서 해당 column만 이제 가져옵시다. name을 채우지 맙시다. row의 해당 column에 기록합니다. “사용하지 않을지 모르는 항목을 위한 작업을 최대한 뒤로 미루자.”

12. 보일러플레이트

13. 보일러플레이트 public class City { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 프로그래머에게 직관적인 코드

14. 보일러플레이트 public class City { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class LazyCity { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 프로그래머에게 비관적인 코드 꼭 이렇게 짜야하나요?

15. 보일러플레이트 public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City{ private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 반복적인 작업은 기계에게 맡겨야 합니다. “Annotation Processing Tool (APT)” 생성된 클래스는 모두 RealmProxy가 붙습니다.Realm 객체는 RealmObject를 상속 받습니다.

16. 반복적인 작업은 기계에게 맡겨야 합니다.

 “Annotation Processing Tool (APT)” 

“어노테이션 프로세싱 툴은 어노테이션으로 부터 새로운 객체를 생성합니다.”


17. Man vs Code 

City CityRealmProx y 사용자의 원본 객체 (RealmObject) 기계가 생성한 객체 (RealmProxy) 어노테이션 프로세싱 툴 (APT)


18. Man vs Code Realm의 APT는 AbstractProcessor를 상속한 RealmProcessor로 구현됩니다. AbstractProcessor +process(annotations, roundEnv) RealmProcessor RealmObject RealmProxy RealmObject RealmProxy RealmObject RealmProxy

19. Man vs Code writer.emitAnnotation("Override") .beginMethod( "void", // return type "copy", // method name EnumSet.of(Modifier.PROTECTED, Modifier.FINAL), // modifiers "ColumnInfo", "rawSrc", "ColumnInfo", "rawDst"); // parameters writer.emitStatement("final %1$s src = (%1$s) rawSrc", columnInfoClassName()); writer.emitStatement("final %1$s dst = (%1$s) rawDst", columnInfoClassName()); for (VariableElement variableElement : metadata.getFields()) { writer.emitStatement("dst.%1$s = src.%1$s", columnIndexVarName(variableElement)); } writer.endMethod(); “마법은 없습니다. Java 코드를 생성하는 것은 고통스러운 일입니다.”

20. Man vs Code “마법은 없습니다. Java 코드를 생성하는 것은 고통스러운 일입니다.” 1. StringBuilder 2. Template engines 1. Apache Velocity (7년만에 부활) 2. Apache FreeMaker 3. Pebble Template Engine 4. Thymeleaf Template Engine 3. Code generators 1. JavaPoet 2. JavaWriter (개발 중단. Java Poet이 후속작) 3. jcodemodel (2005년 경부터 개발 중단) 당신은 용자 코드도 찍어내면 그만? 내가 코드를 짜는 건지 코드가 날 짜는 건지. 튜토리얼이 많은 애가 개발이 잘 안돼. 그래도 스퀘어가 제일 낫지 않나?

21. APT가 해법인가?

22. APT가 해법인가? public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } APT는 어떤 메서드가 어떤 역할인지 이해하지 못합니다.

23. APT가 해법인가? public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 암묵적인 컨벤션을 가정합니다. 구 버전의 Realm에서는 항상 표준적인 이름의 getter와 setter를 강제합니다. name이란 필드에 대해 getName과 setName을 쓰지 않을까요?

24. APT가 해법인가? public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 부모가 name 필드와 어떤 상호작용을 하고 있을지 예상할 수 없습니다. 구 버전의 Realm은 커스텀 동작을 금지하고 부모 클래스의 동작을 무시했습니다. City의 getName은 어떤 부가 작업을 하고 있을까요? City의 setName은 어떤 부가 작업을 하고 있을까요?

25. 바이트 코드 뒤집기

26. 바이트 코드 뒤집기 City name CityRealmProx y CityRealmProxyInterface +realmGet$name: String +realmSet$name(name) ZeroCopy관련 객체를 위한 인터페이스 name 필드에 접근하는 모든 코드 대신 realmGet$name과 realmSet$name이 호출되도록 변조합 니다. realmGet$name과 realmSet$name를 오버라이드해서 Zero copy 부분을 구현합니다. APT로 코드 생성 인터페이스 구현

27. 바이트 코드 뒤집기 public class CityRealmProxy extends City implements CityRealmProxyInterface { private final int COLUMN_NAME = 0; public String realmGet$name() { return (String) getRow().getSting(COLUMN_NAME); } public void realmSet$Name(String name) { getRow().setString(COLUMN_NAME, name); } } 내부용 게터와 세터는 RealmProxy 아래 생성됩니다.

28. 바이트 코드 뒤집기 public class City implements CityRealmProxyInterface { private String name; public String getName() { return (String) realmGet$name(); } public void setName(String name) { realmSet$name(name); } public String realmGet$name() { return name; } public void realmSet$Name(String name) { this.name = name; } } “바이트코드가 변조된 City객체 입니다.” public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }

29. 바이트 코드 뒤집기 public class City implements CityRealmProxyInterface { public String name; public String realmGet$name() { return name; } public void realmSet$Name(String name) { this.name = name; } } “이제는 getter와 setter가 없어도 됩니다.” public class City extends RealmObject { public String name; } name 필드에 대한 접근은 모두 게터와 세터 호출로 변경됩니다.

30. 바이트 코드 뒤집기 City CIty 사용자가 생성한 객체 바이트 코드 변조된 객체 Transformer “Transformer는 빌드된 결과를 변조합니다.”

31. 바이트 코드 뒤집기 class RealmTransformer extends Transform { @Override void transform(Context context, Collection<TransformInput> inputs, Collection<TransformInput> referencedInputs, TransformOutputProvider outputProvider, boolean isIncremental) throws IOException, TransformException, InterruptedException { … } } 이 트랜스포머가 필드에 대한 접근들을 모두 Realm의 게터와 세터로 변조합니다.

32. 바이트 코드 뒤집기 “마법은 없습니다. 바이트 코드를 변조하는 것은 고통스러운 일입니다.” 1. ASM 2. BCEL 3. CGLIB 4. Javassist 5. AspectJ 중간 정도 난이도의 도구. Realm이 사용.

33. 다른 DB도 Zero copy?

34. 다른 DB도 Zero copy? SQLite 시스템 적인 경계 Object Object Object Object Object Object ORM

35. 다른 DB도 Zero copy? SQLite 시스템 적인 경계 Object Object Object Object Object Object ORM 이 영역까지만 lazy하게 미룰 수 있음.

36. 다른 DB도 Zero copy? SQLite 시스템 적인 경계 Object Object Object Object Object Object ORM 경계를 넘어서 lazy한 처리는 어려움.

37. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; “Realm은 생각보다 더 게으릅니다.”

38. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; Realm 은 오프셋도 리미트도 없습니다.

39. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; 이 시점에서는 실제 데이터를 받아오지 않습니다. 실제 데이터를 가지고 있지 않기 때문에 특수한 리스트 구조를 가지고 있습 니다.

40. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; 이 시점에 첫 번째 사람에 대한 메타 데이터만 가지고 옵니다.

41. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; 이 시점에 첫 번째 사람의 정보 중 name만 접근합니다.

42. 더 많은 Zero copy 가능성 Realm은 lazy하게 동작하기 위해 특별한 클래스를 가집니다. 1. RealmObject 2. RealmResults 3. RealmList DB 엔진의 지원 때문에 전체적으로 게을러질 수 있습니다.

43. 조금 더 빨라지기 위 해

44. 조금 더 빨라지기 위해 final RealmResults<Person> people = realm.where(Person.class).findAll(); for (Person person : people) { final String name = person.name; } 객체의 전체 필드가 필요한 경우는 드뭅니다. 모바일 데이터베이스의 특징을 생각해봅시다.

45. 조금 더 빨라지기 위해 10 30 40 3 4 6 10 Row 3 전통적인 Row 우선 B-Tree리프가 10번째 Row까지 가진다는 것을 의미 nam e votes 패딩 리프는 보통 연속된 Array Row에 속한 모든 Column

46. 조금 더 빨라지기 위해 10 30 40 3 4 6 10 Row 3 연속된 name 검색 nam e votes 패딩 인접한 데이터는 name이 아니다.

47. 조금 더 빨라지기 위해 캐시를 생각해봅시다. (3회 적중) nam e votes 패딩 nam e votes 패딩 nam e votes 패딩 nam e votes 패딩 캐시 라인 캐시 히트 캐시 미스

48. 조금 더 빨라지기 위해 구조를 컬럼 기준으로 바꾸어봅시다. nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e 캐시 라인

49. 조금 더 빨라지기 위해 구조를 컬럼 기준으로 바꾸어봅시다. (12회 적중) nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e 캐시 라인 캐시 히트 캐시 미스

50. 조금 더 빨라지기 위해 4 8 12 Realm의 Column 우선 B-Tree nam e nam e nam e nam e 리프가 4번째 컬럼까지 가진다는 것을 의미 동질적인 데이터이기에 예측가능한 사이즈

51. 4 8 12 Realm의 전체 트리 nam e nam e nam e nam e nam e votes Perso n Group (DB와 같은 개념) Table Column B-tree 4 8 12 vote votes votes votes Ro ot

52. Root가 있는 이유?

53. Root가 있는 이유? 4 8 12 nam e nam e nam e nam e nam e votes Perso n 4 8 12 vote votes votes votes Ro ot 전체 Group을 하나의 스냅샷으로 인 지.

54. Root가 있는 이유? 현재 버전을 포인팅 Ro ot 현재 버전 삭제될 과거 버전 “Multi Version Concurrency Control” Git, 현대적인 DBMS에서 사용.

55. Root가 있는 이유? Ro ot 다른 사용자는 현재 버전에 Lock 없이 접근. 새 버전을 작성중 . 읽기는 언제나 비 배타적입니다.

56. Root가 있는 이유? Ro ot 새로 작성된 버전으로 옮겨가는 것만 락이 필요합 니다. Ro ot 쓰기만 배타적입니다. 다른 사용자는 여전히 이전 버전에 접근 중. 루트를 이동

57. Root가 있는 이유? "MVVC는 효율을 위해 사용성을 일부 희생합니다.” 1. 읽기는 Lock이 필요하지 않으며 언제나 가능합니다. 2. 쓰기는 Lock이 필요합니다. 3. 객체는 어떤 시점을 참고하고 있기 때문에 다른 스레드로 전달될 수 없습니 4. 다른 스레드에서 객체를 참고하는 것은 즉시 이루어집니다. 프로그래머에게 직관적이지는 않습니다.

58. 이전 버전을 읽을 가 능성?

59. 이전 버전을 읽을 가능성? Ro ot 다른 사용자는 현재 버전에 Lock 없이 접근. 새 버전을 작성중 . “다른 사용자는 여전히 구 버전을 접근하게 되지 않나요?”

60. 이전 버전을 읽을 가능성? Person 객체 (Leonardo) v1 Person 객체 (Leonardo) v1 스레드 A 스레드 B Person 객체 (Leonardo) v2 1. 스레드 A에서 Person 객체 업데이트. 2. 업데이트 내역이 전파. Person 객체 (Leonardo) v2 3. 스레드 B의 라이브 객체가 자동 업데이 트. 3. 스레드 B의 객체의 리스너에게 모두 업데이트 내용을 통보.

61. 추가적인 최적화

62. 추가적인 최적화 4 8 12 nam e nam e nam e nam e nam e votes Perso n 배열은 얼마나 많은 공간을 차지할까? 4 8 12 vote votes votes votes Ro ot

63. 추가적인 최적화 0 1 0 1 votes가 최대 1인 경우 “최대 값이 1인 경우 4개의 votes는 4bits를 차지합니다.” Boolean 타입이 가장 효율적으로 저장됩니다.

64. 추가적인 최적화 00 01 10 01 최대 값이 2로 변경되었습니다. “최대 값이 2인 경우 4개의 votes는 8bits를 차지합니다.”

65. 추가적인 최적화 000 101 010 001 최대 값이 5로 변경되었습니다. “최대 값이 5인 경우 4개의 votes는 12bits를 차지합니다.”

66. 추가적인 최적화 4 8 12 노드의 실제 구조 nam e nam e nam e nam e nam e votes Perso n 4 8 12 vote votes votes votes Ro ot 4 8 12 개별 노드는 3개의 배열을 사용합니 다. 유연하지만 오버헤드가 있습니다.

67. 추가적인 최적화 nam e votes Perso n vote votes votes votes 4 8 12 만약에 데이터가 뒤로만 추가된다면 더 최적화를 할 수 있습니 다. 모든 노드가 다 차있다면 처음과 마지막 인덱스만 있으면 됩 니다.

68. 추가적인 최적화 nam e votes Perso n vote votes votes votes 4 12 물론 이러한 꿈은 삽입과 삭제가 이뤄지면 물거품이 됩니다. 모든 노드가 다 차있다면 처음과 마지막 인덱스만 있으면 됩 니다.

69. 흥미로운가요?


70. 기회는 여러분에게 열려있습니다. “Realm은 오픈소스입니다.”

Realm Java https://github.com/realm/realm-java 

Realm Objective C & Swift https://github.com/realm/realm-cocoa 

Realm Xamarin https://github.com/realm/realm-dotnet 

Realm Reactive Native & Node.js https://github.com/realm/realm-js 

Realm Object Store 공통 모듈 https://github.com/realm/realm-object-store 

Realm Core 핵심 엔진 https://github.com/realm/realm-core


71. Realm을 바로 사용하실 수 있습니다. 

Realm Java 문서 https://realm.io/docs/java/latest/ 

Realm Swift 문서 https://realm.io/docs/swift/latest/ 

Realm Objective C 문서 https://realm.io/docs/objc/latest/ 

Realm React Native 문서 https://realm.io/docs/javascript/latest/ 

Realm Xamarin 문서 https://realm.io/docs/xamarin/latest/

72. 최신 모바일 기술은 Realm에서 https://realm.io

73. Thank you



...

반응형
반응형

[APP] AWS 모바일 - AWS에서 모바일 앱을 구축하는 가장 빠른 방법


https://aws.amazon.com/ko/mobile/


모바일 앱을 구축하는 데 필요한 모든 것


다양한 클라우드 서비스 세트

AWS에서는 확장성이 뛰어난 완전관리형 서비스를 다양하게 제공하고 있으므로 인프라를 관리할 필요 없이 로직, 스토리지, 데이터베이스, 모니터링, 스트리밍, 콘텐츠 전송, 데이터 웨어하우징 및 기계 학습 같은 기능을 앱에 추가할 수 있습니다.


구축에 도움이 되는 도구

AWS를사용하면 손쉽게 클라우드 서비스를 모바일 앱에 추가할 수 있습니다. 서버 없는 모바일 백엔드를 생성하고, 사용자 자격 증명과 로그인을 관리합니다. 푸시 알림을 전송하고, 사용 패턴을 추적하며, 인앱 분석으로 앱을 최적화합니다. 다양한 실제 디바이스에서 테스트합니다.







...

반응형

+ Recent posts