🙂 İNSANLARIN EN HAYIRLISI INSANLARA FAYDALI OLANDIR 🙂

Ramazan HABER / FLUTTER / URL strategy on the web

1-) FLUTTER - URL strategy on the web

 

kaynak : https://docs.flutter.dev/ui/navigation/url-strategies

 

 

flutter web url temizleme

flutterexample.dev/#/path/to/screen

flutterexample.dev/path/to/screen.

 

 

📝 Flutter Web Routing - Basit Notlar

// main.dart

import 'package:flutter_web_plugins/url_strategy.dart';

 

void main() {

  usePathUrlStrategy(); // Temiz URL'ler için

  runApp(MyApp());

}

 

 

MaterialApp(

  home: HomeScreen(), // Ana sayfa

  routes: {

    '/sepet': (context) => CartScreen(),

    '/gizlilik': (context) => PrivacyScreen(),

    '/iletisim': (context) => ContactScreen(),

  },

)

 

// Sayfa geçişi

Navigator.pushNamed(context, '/gizlilik');

 

 

 

linke doğrudan gidildiğinde açması için ve genel route yapısı


# Flutter Web SPA Configuration

 

## Problem

Flutter Web SPAs have routing issues when users access URLs directly (e.g., `/sepet`, `/gizlilik`). Server returns 404 because physical files don't exist.

 

## Solution

Create configuration files for all hosting platforms to redirect all requests to `index.html`.

 

## Configuration Files

 

### 1. web/_redirects (Netlify/Vercel)

```

/*    /index.html   200

```

 

### 2. web/web.config (IIS/Windows)

```xml

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

  <system.webServer>

    <rewrite>

      <rules>

        <rule name="Flutter Routes" stopProcessing="true">

          <match url=".*" />

          <conditions logicalGrouping="MatchAll">

            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />

            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />

          </conditions>

          <action type="Rewrite" url="/" />

        </rule>

      </rules>

    </rewrite>

  </system.webServer>

</configuration>

```

 

### 3. web/nginx.conf (Nginx)

```nginx

server {

    listen 80;

    server_name _;

    root /usr/share/nginx/html;

    index index.html;

 

    location / {

        try_files $uri $uri/ /index.html;

    }

 

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {

        expires 1y;

        add_header Cache-Control "public, immutable";

    }

}

```

 

### 4. web/.htaccess (Apache)

```apache

RewriteEngine On

RewriteBase /

 

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule . /index.html [L]

 

<FilesMatch "\.(js|css|png|jpg|jpeg|gif|ico|svg)$">

    ExpiresActive On

    ExpiresDefault "access plus 1 year"

    Header set Cache-Control "public, immutable"

</FilesMatch>

```

 

## Clean index.html

```html

<!DOCTYPE html>

<html>

<head>

  <base href="$FLUTTER_BASE_HREF">

  <meta charset="UTF-8">

  <meta content="IE=Edge" http-equiv="X-UA-Compatible">

  <meta name="description" content="Your App Description">

  <title>Your App Title</title>

  <link rel="manifest" href="manifest.json">

</head>

<body>

  <script src="flutter_bootstrap.js" async></script>

</body>

</html>

```

 

## Build Command

```bash

flutter build web

```

 

## URL Strategy Configuration

 

### 1. Add dependency to pubspec.yaml

```yaml

dependencies:

  flutter_web_plugins:

    sdk: flutter

```

 

### 2. Configure in main.dart

```dart

import 'package:flutter/foundation.dart';

import 'package:flutter_web_plugins/url_strategy.dart';

 

void main() {

  WidgetsFlutterBinding.ensureInitialized();

 

  // Enable path-based URLs for web

  if (kIsWeb) {

    usePathUrlStrategy();

  }

 

  runApp(const MyApp());

}

```

 

## Route Structure Example

 

### 1. Main Layout with Navigation

```dart

// lib/widgets/main_layout.dart

class MainLayout extends StatelessWidget {

  final Widget child;

  final String currentRoute;

 

  const MainLayout({

    super.key,

    required this.child,

    required this.currentRoute,

  });

 

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      body: Column(

        children: [

          // Navigation Bar

          Container(

            color: Colors.orange,

            child: Row(

              children: [

                _buildNavItem('Ana Sayfa', '/', Icons.home),

                _buildNavItem('Sepet', '/sepet', Icons.shopping_cart),

                _buildNavItem('İletişim', '/iletisim', Icons.contact_mail),

                _buildNavItem('Gizlilik', '/gizlilik', Icons.privacy_tip),

              ],

            ),

          ),

          // Main Content

          Expanded(child: child),

          // Footer

          const FooterWidget(),

        ],

      ),

    );

  }

 

  Widget _buildNavItem(String title, String route, IconData icon) {

    final isSelected = currentRoute == route;

    return GestureDetector(

      onTap: () => Navigator.pushNamed(context, route),

      child: Container(

        padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),

        decoration: BoxDecoration(

          color: isSelected ? Colors.white.withValues(alpha: 0.2) : Colors.transparent,

          borderRadius: BorderRadius.circular(20),

        ),

        child: Row(

          mainAxisSize: MainAxisSize.min,

          children: [

            Icon(icon, color: Colors.white, size: 18),

            const SizedBox(width: 6),

            Text(title, style: const TextStyle(color: Colors.white, fontSize: 14)),

          ],

        ),

      ),

    );

  }

}

```

 

### 2. App Routes Configuration

```dart

// lib/main.dart

class MyApp extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    return MaterialApp(

      title: 'Your App',

      theme: ThemeData(

        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),

        useMaterial3: true,

      ),

      home: MainLayout(

        currentRoute: '/',

        child: HomeScreen(),

      ),

      routes: {

        '/': (context) => MainLayout(

          currentRoute: '/',

          child: HomeScreen(),

        ),

        '/sepet': (context) => MainLayout(

          currentRoute: '/sepet',

          child: CartScreen(),

        ),

        '/iletisim': (context) => MainLayout(

          currentRoute: '/iletisim',

          child: ContactScreen(),

        ),

        '/gizlilik': (context) => MainLayout(

          currentRoute: '/gizlilik',

          child: PrivacyScreen(),

        ),

        '/checkout': (context) => MainLayout(

          currentRoute: '/checkout',

          child: CheckoutScreen(),

        ),

      },

      debugShowCheckedModeBanner: false,

    );

  }

}

```

 

### 3. Screen Examples

```dart

// lib/screens/home_screen.dart

class HomeScreen extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      backgroundColor: Colors.grey[100],

      body: Center(

        child: Text('Ana Sayfa'),

      ),

    );

  }

}

 

// lib/screens/cart_screen.dart

class CartScreen extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      backgroundColor: Colors.grey[100],

      body: Center(

        child: Text('Sepet'),

      ),

    );

  }

}

```

 

## Payment Logos Best Practices

 

### Use PNG files instead of SVG

- Avoid `flutter_svg` dependency

- Use `Image.asset()` for all logos

- Create reusable `FooterWidget`

 

### FooterWidget Example

```dart

// lib/widgets/footer_widget.dart

import 'package:flutter/material.dart';

 

class FooterWidget extends StatelessWidget {

  const FooterWidget({super.key});

 

  @override

  Widget build(BuildContext context) {

    return Container(

      padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20),

      decoration: BoxDecoration(

        color: Colors.grey[100],

        border: Border(top: BorderSide(color: Colors.grey[300]!)),

      ),

      child: Row(

        mainAxisAlignment: MainAxisAlignment.center,

        children: [

          Text('Güvenli Ödeme'),

          SizedBox(width: 12),

          // Payment logos here

        ],

      ),

    );

  }

}

```

 

### Usage in screens

```dart

import '../widgets/footer_widget.dart';

 

// In build method:

const FooterWidget()

```

 

## Benefits

- Direct URL access works (`/sepet`, `/gizlilik`)

- Works on all hosting platforms

- No CanvasKit errors (uses HTML renderer)

- Clean, maintainable code

- Proper caching for static assets

 

 2025 Ekim 21 Salı
 97